我目前有一段代码可以生成多个进程,如下所示:
pool = Pool(processes=None)
results = [pool.apply(f, args=(arg1, arg2, arg3)) for arg3 in arg_list]
我的想法是,这将使用自processes=None
以来可用的所有核心来划分核心工作。但是,multiprocessing module docs中Pool.apply()
方法的文档为:
apply()内置函数的等效项。它会一直阻塞,直到结果准备就绪,因此apply_async()更适合并行执行工作。此外,func仅在池中的一个工作程序中执行。
第一个问题:
我不清楚这一点。 apply
如何在工作人员之间分配工作,以及它与apply_async
的工作方式有何不同?如果任务分布在工作人员之间,func
如何仅在其中一个工作人员中执行?
我的猜测:我的猜测是,在我当前的实现中,apply
正在向具有一组参数的工作者提供任务,然后等待该工作者完成,然后将下一组参数提供给另一个工人。通过这种方式,我将工作发送到不同的流程,但没有发生并行性。这似乎是这种情况,因为apply
实际上只是:
def apply(self, func, args=(), kwds={}):
'''
Equivalent of `func(*args, **kwds)`.
Pool must be running.
'''
return self.apply_async(func, args, kwds).get()
第二个问题:我还想更好地了解为什么在引入docs第16.6.1.5节时。 ('使用一群工人'),他们说即使是apply_async
的建筑,如
[pool.apply_async(os.getpid, ()) for i in range(4)]
可能使用更多进程,但它不确定它会。 决定是否使用多个流程的原因是什么?
答案 0 :(得分:1)
您已经指出了Python2.7文档,因此我将基于Python2.7多处理实现来获得答案。它可能在Python3.X上有所不同,但不应该有很大不同。
apply
和apply_async
当你查看这些实际上是如何实现它们时,这两者之间的区别实际上是自我描述的。在这里,我将从multiprocessing/pool.py
复制/粘贴代码以获取机器人函数。
def apply(self, func, args=(), kwds={}):
'''
Equivalent of `apply()` builtin
'''
assert self._state == RUN
return self.apply_async(func, args, kwds).get()
如您所见,apply
实际上正在调用apply_async
,但在返回结果之前,会调用get
。这基本上会使apply_async
阻塞,直到返回结果。
def apply_async(self, func, args=(), kwds={}, callback=None):
'''
Asynchronous equivalent of `apply()` builtin
'''
assert self._state == RUN
result = ApplyResult(self._cache, callback)
self._taskqueue.put(([(result._job, None, func, args, kwds)], None))
return result
apply_async
将任务队列中的任务排队,并返回已提交任务的handle
。使用handle
,您可以分别调用get
或wait
来获取结果或等待任务完成。任务完成后,它返回的内容将作为参数传递给callback
函数。
from multiprocessing import Pool
from time import sleep
def callback(a):
print a
def worker(i, n):
print 'Entering worker ', i
sleep(n)
print 'Exiting worker'
return 'worker_response'
if __name__ == '__main__':
pool = Pool(4)
a = [pool.apply_async(worker, (i, 4), callback=callback) for i in range(8)]
for i in a:
i.wait()
Entering worker 0
Entering worker 1
Entering worker 2
Entering worker 3
Exiting worker
Exiting worker
Exiting worker
Exiting worker
Entering worker 4
Entering worker 5
worker_response
Entering worker 6
worker_response
Entering worker 7
worker_response
worker_response
Exiting worker
Exiting worker
Exiting worker
Exiting worker
worker_response
worker_response
worker_response
worker_response
请注意,使用apply_async
时,您必须等待结果或等待任务完成。如果你没有评论我的例子的最后两行,你的脚本将在你运行后立即完成。
apply_async
可能会使用更多进程我理解这与apply
如何描述和工作有关。由于apply
通过任务将任务发送到Pool
中的可用进程来运行任务,apply_async
将任务添加到队列,然后任务队列线程将它们发送到Pool
中的可用进程。这就是使用apply_async
时可能会运行多个进程的原因。
我经历了几次this部分,以便更好地理解作者试图传达的想法。让我们在这里查看:
# evaluate "os.getpid()" asynchronously
res = pool.apply_async(os.getpid, ()) # runs in *only* one process
print res.get(timeout=1) # prints the PID of that process
# launching multiple evaluations asynchronously *may* use more processes
multiple_results = [pool.apply_async(os.getpid, ()) for i in range(4)]
print [res.get(timeout=1) for res in multiple_results]
如果我们通过查看上一个示例来尝试理解最后一个示例,当您有多个apply_async
的连续调用时,肯定可能同时运行更多这些调用。这可能取决于当时Pool
中使用了多少进程。这就是为什么他们说可能。