我有一个工作代码,但不确定这是正确的方法。我有两个函数,都发出 API 请求,可能需要 1 到 5 秒之间的任意时间,但两者都旨在返回相同的输出。我想同时运行两者,一旦更快的完成它的工作,终止另一个并丢弃它会返回的任何内容。
p1 = Process(target = search1, args=(name) )
p2 = Process(target = search2, args=(name) )
if __name__=='__main__':
p1.start()
p2.start()
while p1.is_alive() and p2.is_alive():
time.sleep(0.2)
if not p1.is_alive():
p2.terminate()
if not p2.is_alive():
p1.terminate()
如果我不等待一段时间(在本例中为 0.2 秒),如果两者都花费相同的时间,有时两者都会返回。我测试了很多次并且它有效,但这是正确的方法吗?这种方法是否会出现任何问题?
---ti7 建议
在 ti7 的建议之后尝试使用线程,现在它适用于线程而不是进程。
def search1(Q_result, name):
result = somefunction()
Q_result.put(result)
def search2(Q_result, name):
time.sleep(10)
result = somefunction()
Q_result.put(result )
import Queue as queue
import threading
Q_result = queue.Queue() # create a Queue to hold the result(s)
if __name__=='__main__':
t1 = threading.Thread(
target=search1,
args=(Q_result, name),
)
t1.daemon = True
t1.start()
t2 = threading.Thread(
target=search2,
args=(Q_result),
)
t2.daemon = True
t2.start()
print(Q_result.get())
如果您多次发出相同的请求,则最好只执行一次并联系服务的所有者以提高其性能。(例如,它可能正在分发连接,其中一个节点非常慢)。
正如@Arty所指出的,使用线程的创建比进程更轻,因此性能更高。您可以将线程设置为守护进程,这样它们就不需要.join()
ed 即可退出(阻止程序退出,直到所有线程都完成)。
异步逻辑可能仍然快一点,但推理起来可能会令人沮丧,尤其是在 Python 2 中。此外,您可能会发现,如果您使用的是第三方库(例如 Twisted 的 Defferred),加载所需的库会非常慢并降低整体性能。
使用线程,您可能会发现获取结果并将其放入queue.Queue
中很方便,这既是线程安全的,又可以在内容可用之前阻止。
粗螺纹示例
from __future__ import print_function # print(x) over print x
import queue
import threading
# if these are the same logic, use an argument to differentiate
# otherwise you could have any number of unique functions,
# each of which makes some different request
def make_request(Q_result, request_args):
result = "whatever logic is needed to make request A"
Q_result.put(result) # put the result into the Queue
list_of_different_request_args = [] # fill with whatever you need
Q_result = queue.Queue() # create a Queue to hold the result(s)
# iterate over input args (could be list of target functions instead)
for request_args in list_of_different_request_args:
t = threading.Thread(
target=make_request,
args=(Q_result, request_args),
)
t.daemon = True # set via arg in Python 3
t.start()
# get the first result, blocking until one is available
print(Q_result.get())
# program exits and discards threads