了解Python多处理apply\u aync和get

了解Python多处理apply\u aync和get,python,multiprocessing,Python,Multiprocessing,我在翻阅我不久前写的一些代码,它有如下结构。我试图在需要的地方添加解释性评论 #创建读写器进程 reader\u proc=Process(target=self.reader) 读卡器程序启动() writer\u proc=Process(target=self.writer,args=(pfin,)) 写入程序启动() #组建一批工人 将池(n个工作线程,maxstasksperchild=max_tasks_per_child)作为池: #记录工人的名单 工人职位=[] #用于跟踪返回值

我在翻阅我不久前写的一些代码,它有如下结构。我试图在需要的地方添加解释性评论

#创建读写器进程
reader\u proc=Process(target=self.reader)
读卡器程序启动()
writer\u proc=Process(target=self.writer,args=(pfin,))
写入程序启动()
#组建一批工人
将池(n个工作线程,maxstasksperchild=max_tasks_per_child)作为池:
#记录工人的名单
工人职位=[]
#用于跟踪返回值的列表
返回值=[]
#从读取器获取输入块
#读卡器将输入块写入工作队列
尽管如此:
work=work_q.get()
如果工时==“完成”:
打破
#进程块是一个函数,它。。。处理给定的块
#此函数将执行一些计算并将其写入结果(队列)
#然后写入程序会将其写入文件
#该函数还返回下面处理的另一种类型的值
作业=池。应用异步(进程块,(工作)
worker\u jobs.append(作业)
打印('Done reading chunk!')
#读者阅读完毕
reader_proc.join()
读卡器进程终止()
#工人完成工作后,将其信息取回
对于job_idx,枚举中的job(worker_jobs,1):
打印(f“处理作业{job_idx}”)
res1,res2=job.get()
返回值附加((res1,res2))
#主过程中的过程结果
处理结果(返回值)
#通知作者我们完成了
结果_q.put(‘完成’)
Tl;dr池使用
apply\u async
处理队列中的块。队列耗尽后,我们
.get()
返回结果并进行处理

我不确定这些作业是在应用到池时立即执行,还是等到调用
.get()
后才执行?这一点很重要,因为如果它们等待执行直到队列耗尽,那么对于长队列来说,这可能需要很长时间

另一方面,如果它们不等待并立即执行,那么这些函数的结果存储在哪里?由于我们要等到
.get()
才能获取结果,这是否意味着在调用
.get()
之前会阻止子进程


我之所以问这个问题,是因为在第一次打印语句(读取完成)和后续语句(处理作业x)之间有很长的延迟,我不知道为什么。

工作人员一有空,任务就会执行。得到结果或根本得不到结果对这一点没有影响

您的工作人员结果存储在
AsyncResult
对象中,在您的情况下,
job
就是其中之一,并且
worker\u jobs
拥有它们。然后你做正确的事情,循环你的结果对象,得到结果

池将结果存储在内部,直到您获得它们为止—即使您根本没有获得结果,它也不会阻止工作进程—在并行处理的许多情况下,如果工作进程只是基于输入执行特定任务,您甚至可能对工作进程的“结果”不感兴趣。一旦工作进程完成并将结果(或异常!)存储在此对象中,它就可以自由地接受池中的另一个作业

这也意味着您必须在关闭池之前获得结果——就像您现在所做的那样。如果将“处理作业”循环移到带有池的
结构之外,则在尝试获取结果时,结果将丢失

请参阅关于
AsyncResult
对象的可用方法


如果工作人员引发异常,则
AsyncResult
对象还存储异常。它不会在工作进程遇到异常时立即触发,而是存储在那里,并在您得到()结果时引发。如果您的工作者可以引发异常,那么您应该为get循环而不是工作者构建异常处理

工作人员一有空就执行任务。得到结果或根本得不到结果对这一点没有影响

您的工作人员结果存储在
AsyncResult
对象中,在您的情况下,
job
就是其中之一,并且
worker\u jobs
拥有它们。然后你做正确的事情,循环你的结果对象,得到结果

池将结果存储在内部,直到您获得它们为止—即使您根本没有获得结果,它也不会阻止工作进程—在并行处理的许多情况下,如果工作进程只是基于输入执行特定任务,您甚至可能对工作进程的“结果”不感兴趣。一旦工作进程完成并将结果(或异常!)存储在此对象中,它就可以自由地接受池中的另一个作业

这也意味着您必须在关闭池之前获得结果——就像您现在所做的那样。如果将“处理作业”循环移到带有池的
结构之外,则在尝试获取结果时,结果将丢失

请参阅关于
AsyncResult
对象的可用方法


如果工作人员引发异常,则
AsyncResult
对象还存储异常。它不会在工作进程遇到异常时立即触发,而是存储在那里,并在您得到()结果时引发。如果您的工作者可以引发异常,那么您应该为get循环而不是工作者构建异常处理

您可以在reader_proc调用之后添加一条print语句,就在您的“完成阅读块”之后。这只是一个猜测,但延迟可能不是由您的池引起的,而是由您对reader_proc的操作引起的。如果是套接字代码,而你的.join()会等待不必要的时间,那么会有超时吗?@Hannu我按照你的建议做了,并在
Reader\u proc.terminate()语句后放置了一个“Reader terminated”打印,一个