[英]Add unknown number of jobs to pool until a job returns None
假设我们想要发送大量的网络请求,并对我们返回的数据做一些事情。 我们必须对响应进行的数据处理非常繁重,因此我们希望将其并行化:主进程将查询 URL 分配给子进程,然后子进程获取数据并进行一些处理。 够简单! 但我遇到的问题是事先不知道有多少个 URL。 我们知道的唯一方法是当其中一个子进程返回错误时(实际上,当它返回None
时)。
我有两种可能的方法,但都有相同的问题:我似乎无法弄清楚如何处理输入列表(要查询的 URL)大小未知(其动态生成)的事实。
尝试#1 :创建一个队列,设置单独的进程来生成 URL(这里它生成索引)并将它们放入队列中。 然后创建侦听此队列并处理链接的子进程(这里就像获取列表的相应项一样简单,但在超出索引时返回 None - 退出场景)。 问题是我不知道如何告诉作者,一旦其中一个进程产生None
,它就应该停止将事物放入队列中。
注意:此脚本将无限运行,因为编写器没有break
。
from multiprocessing import Pool, Process, Queue
RESPONSES = ["hello", "this", "is", "a", "response", "to", "your", "request"] # We do not know this length
def send_request(idx):
try:
return RESPONSES[idx]
except IndexError:
return None
def worker(q):
while True:
# Get work from the working queue
idx = q.get()
resp = send_request(idx)
print(resp)
def writer(q):
idx = 0
while True: # How can I stop this when any response is None
q.put(idx)
idx += 1
def main():
work_q = Queue()
writer_proc = Process(target=writer, args=(work_q,))
writer_proc.start()
pool = Pool(3, worker, (work_q,))
pool.close()
pool.join()
writer_proc.join()
writer_proc.terminate()
if __name__ == '__main__':
main()
尝试#2:这是一种涉及较少的方法(无队列),它在池上使用apply_async
来不断添加可以检查的新 URL。 但是在这里,我不知道一旦其中一名工人发回None
,如何打破那个 while 循环。
from multiprocessing import Pool
RESPONSES = ["hello", "this", "is", "a", "response", "to", "your", "request"]
def send_request(idx):
try:
return RESPONSES[idx]
except IndexError:
return None
def main():
with Pool(3) as pool:
idx = 0
while True: # Can't make this loop within fixed range because we do not know how many responses there are
pool.apply_async(send_request, (idx,))
idx += 1
# How do I break out here as soon as a request returns None
if __name__ == '__main__':
main()
简而言之:如果我事先不知道要完成多少工作,或者更确切地说 - 这取决于工人的反应是否增加更多工作,我如何才能在 Python 中使用一组工人来完成这项工作?
这些创建可以通过子进程访问的共享内存,并反映任何进程对它们所做的任何更改。 因此,像这样创建一个共享标志:
import multiprocessing
from ctypes import c_bool
.
.
.
if __name__ == "__main__":
# Create flag with inital value True
flag = multiprocessing.Value(c_bool, "True")
然后将此标志传递给您创建的每个进程。 然后,当您不再想发送请求时,您可以从send_request
内部执行以下操作。
flag.value = False
此外,编辑您的writer
以检查标志是否在while
语句中设置为True
(请记住需要使用.value
属性访问存储的值!):
while flag.value:
请记住,共享内存不是线程安全的。 虽然这不应该影响您的情况,因为您只是将其用作标志,但您可以在创建标志以在内部使用锁时指定lock=True
关键字参数
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.