了解一个简单的多处理脚本

时间:2016-03-20 18:08:13

标签: python python-3.x multiprocessing pool

我试图理解Python的多处理模块是如何工作的。为此,我制作了一个非常简单的代码版本,并尝试使其并行工作。根据我的阅读,使用pool比使用mp.Process更适合我的程序。

以下是我提出的建议:

import time, os
import multiprocessing as mp

class Foo:
    def __init__(self, ID):
        self.ID = ID

    def showID(self):
        for k in range(0,4):
            print('Foo #', self.ID, '\tID:', os.getpid(), '\tParent ID:', os.getppid())
            time.sleep(0.2)

# MAIN
if __name__ == '__main__':

    print('parent process:', os.getppid())
    print('process id:', os.getpid())
    print(' ')

    foos = [Foo(2), Foo(3)]

    pool = mp.Pool(processes=2)

    # Code below doesn't work
    pool.apply_async(foos[0].showID, ())
    pool.apply_async(foos[1].showID, ())

列表foos最终将包含10到20个对象。方法Foo.showID最终也会返回一些东西。我的目标是在它们运行时发送尽可能多的任务(foos成员),以便将它们分派到pool个进程之一。

如果我运行上面的代码,没有任何反应,即。仅显示开头的parent processprocess id。如果我将最后两行替换为:

pool.apply_async(foos[0].showID())
pool.apply_async(foos[1].showID())

它们都是在主进程中一个接一个地执行的:

parent process: 3380
process id: 6556

Foo # 2         ID: 6556        Parent ID: 3380
Foo # 2         ID: 6556        Parent ID: 3380
Foo # 2         ID: 6556        Parent ID: 3380
Foo # 2         ID: 6556        Parent ID: 3380
Foo # 3         ID: 6556        Parent ID: 3380
Foo # 3         ID: 6556        Parent ID: 3380
Foo # 3         ID: 6556        Parent ID: 3380
Foo # 3         ID: 6556        Parent ID: 3380

最后,如果我用这样的东西替换它们:

pool.apply_async(foos[0].showID, ())
pool.apply_async(foos[1].showID())

我得到了预期的行为(我认为):

parent process: 3380
process id: 4772

Foo # 3         ID: 4772        Parent ID: 3380
Foo # 2         ID: 6364        Parent ID: 4772
Foo # 3         ID: 4772        Parent ID: 3380
Foo # 2         ID: 6364        Parent ID: 4772
Foo # 3         ID: 4772        Parent ID: 3380
Foo # 2         ID: 6364        Parent ID: 4772
Foo # 3         ID: 4772        Parent ID: 3380
Foo # 2         ID: 6364        Parent ID: 4772

这里发生了什么?如果我尝试使用未在Foo类中定义的函数,我注意到了相同的行为。

2 个答案:

答案 0 :(得分:1)

apply_async收到一个功能

当您使用没有括号的foos[0].showID时,您正在传递函数,而不是调用它,但是在执行时

pool.apply_async(foos[0].showID())

您首先评估foos[0].showID(),然后将其返回值作为参数传递给apply_async。最终进行评估的是apply_async的调用者和同步处理。

这相当于:

foos[0].showID()
pool.apply_async()
foos[1].showID()
pool.apply_async()

您的第一次尝试失败,因为您没有等待异步调用执行。打电话后。

pool.apply_async(foos[0].showID, ())
pool.apply_async(foos[1].showID, ())

您的程序退出,因此您不必等待输出。

最后

pool.apply_async(foos[0].showID, ())
pool.apply_async(foos[1].showID())

相当于:

pool.apply_async(foos[0].showID, ())
foos[1].showID()

进行一次异步通话和一次同步通话,这样就可以了。

答案 1 :(得分:1)

原始代码的问题在于您没有等待子进程执行工作。您安排了工作项并退出导致池杀死了工作人员。在计划作业时保留返回的结果对象并等待它们完成。

import time, os
import multiprocessing as mp

class Foo:
    def __init__(self, ID):
        self.ID = ID

    def showID(self):
        for k in range(0,4):
            print('Foo #', self.ID, '\tID:', os.getpid(), '\tParent ID:', os.getppid())
            time.sleep(0.2)

# MAIN
if __name__ == '__main__':

    print('parent process:', os.getppid())
    print('process id:', os.getpid())
    print(' ')

    foos = [Foo(2), Foo(3)]

    pool = mp.Pool(processes=2)

    results = []
    results.append(pool.apply_async(foos[0].showID, ()))
    results.append(pool.apply_async(foos[1].showID, ()))

    for result in results:
        result.wait()