Python多处理模块

时间:2018-02-15 12:22:03

标签: python parallel-processing multiprocessing

我目前有一段代码可以生成多个进程,如下所示:

pool = Pool(processes=None)
results = [pool.apply(f, args=(arg1, arg2, arg3)) for arg3 in arg_list]

我的想法是,这将使用自processes=None以来可用的所有核心来划分核心工作。但是,multiprocessing module docsPool.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)] 可能使用更多进程,但它不确定它会。 决定是否使用多个流程的原因是什么?

1 个答案:

答案 0 :(得分:1)

您已经指出了Python2.7文档,因此我将基于Python2.7多处理实现来获得答案。它可能在Python3.X上有所不同,但不应该有很大不同。

applyapply_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,您可以分别调用getwait来获取结果或等待任务完成。任务完成后,它返回的内容将作为参数传递给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中使用了多少进程。这就是为什么他们说可能