Python多处理子进程自终止和PickleError

时间:2017-01-26 06:19:51

标签: python multiprocessing decorator

我正在尝试学习多处理模块和装饰器。我对以下代码有两个问题:

from time import sleep
from multiprocessing import Process

class async:
    def __init__(self, function):
        self.func = function
    def __call__(self, *args, **kwargs):
        p = Process(target = self.func, args = args, kwargs = kwargs)
        p.start()

@async
def printA():
    sleep(1)
    print("A")

def main():
    printA()
    printA()
    printA()

    #do more work

if __name__ == "__main__":
    main()
  1. 现在我得到PicklingError: Can't pickle <function printA at 0x00000273F97FF1E0>: it's not the same object as __main__.printA
    我不知道如何解决这个问题。我觉得这是在我的工作unix机上工作,它是Windows的东西吗?

  2. 我希望子进程在完成后自行终止。我尝试在最后使用sys.exit()包装函数,并将其用作Process的目标,但sys.exit()似乎没有正确终止僵尸进程。什么是正确的方法?

  3. 我不想阻止join(),也不想设置daemon=True。最终目标是有人可以导入这个模块,将@async放在任何函数上,它将在一个单独的进程中运行,然后在它到达函数末尾时自行终止。

1 个答案:

答案 0 :(得分:0)

  1. 腌制错误:我可以重现这个问题。在Linux上它运行得很好,在Windows上它没有。问题似乎是在Windows上无法正确腌制的装饰器。删除装饰器会产生这个工作代码(当然,这不是你想要的,但可能会说服你尝试不同的设计方法)。还有this thread on SO也有完全相同的问题。

    from time import sleep
    from multiprocessing import Process
    
    def printA():
        sleep(1)
        print("A")
    
    def main():
        for i in range(3):
            p = Process(target = printA)
            p.start()
    
        #do more work
    
    if __name__ == "__main__":
        main()
    
  2. Zombie进程:为了避免僵尸进程,您需要让父级读取其子级退出代码,需要才能在其中运行join()子进程上的父进程来做到这一点。你可以在装饰器中这样做:

    class async:
        def __init__(self, function):
            self.func = function
            self.pool = []
        def __call__(self, *args, **kwargs):
            p = Process(target = self.func, args = args, kwargs = kwargs)
            self.pool.append(p)
            p.start()
        def __del__(self):
            for p in self.pool:
                p.join()
    
  3. 这使用了python只对@async的一个实例执行的效果,因此您可以收集self.pool中的所有进程。注意,这只是在主进程的出口处运行,因为python不会先删除异步实例。