我正在尝试学习多处理模块和装饰器。我对以下代码有两个问题:
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()
现在我得到PicklingError: Can't pickle <function printA at 0x00000273F97FF1E0>: it's not the same object as __main__.printA
我不知道如何解决这个问题。我觉得这是在我的工作unix机上工作,它是Windows的东西吗?
我希望子进程在完成后自行终止。我尝试在最后使用sys.exit()
包装函数,并将其用作Process的目标,但sys.exit()
似乎没有正确终止僵尸进程。什么是正确的方法?
我不想阻止join()
,也不想设置daemon=True
。最终目标是有人可以导入这个模块,将@async放在任何函数上,它将在一个单独的进程中运行,然后在它到达函数末尾时自行终止。
答案 0 :(得分:0)
腌制错误:我可以重现这个问题。在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()
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()
这使用了python只对@async
的一个实例执行的效果,因此您可以收集self.pool
中的所有进程。注意,这只是在主进程的出口处运行,因为python不会先删除异步实例。