相比于多线程,Python使用多进程的好处就不用多说了,总之一般认识上比多线程跑得快就完事儿了。但能力越大责任越大,多进程的雷区也比较多。这篇文章主要用来排那些咱在实际操作中遇到的雷。
1. OSError: [WinError 87] The parameter is incorrect
在Windows中执行使用了多进程的程序,有时会报这样的错:
Traceback (most recent call last):
...
TypeError: can't pickle _thread.lock objects
...
OSError: [WinError 87] The parameter is incorrect
注意到那行”can’t pickle _thread.lock objects”了吗?一般多进程的定义写成如下形式:
p1 = multiprocessing.Process(target=func, args=(), ...)
Windows下执行多进程时要求给多进程定义传递的参数(即Process()
里的参数)都是可pickle的。也就是说执行pickle.dumps(参数)
不会报错。一般变量、类、函数啥的一般都可以pickle。那什么不可以呢?闭包不可以。我发现自己写的程序里出现了这样的操作:
# 略略略
def func1():
def _func2(x, y):
# 略略略
# 略略略
p1 = multiprocessing.Process(target=_func2, args=(x, y, ))
p1.start()
# 略略略
在这里_func2
就是不可pickle的。就会报错了。
2. 用PyInstaller打包多进程Python代码的麻烦
现在程序不报错了,跑起来了。你准备用PyInstall将代码打包成EXE分发给小伙伴。
打包完成,分发众人。忽闻卧槽,望风而去。之前跑得好端端的程序打了包怎么就报错了呢?看了一眼报错内容:
Traceback (most recent call last):
File "xxx.py", line 61, in <module>
ValueError: invalid literal for int() with base 10: 'pipe_handle=624'
[26420] Failed to execute script 'xxx' due to unhandled exception!
Traceback (most recent call last):
File "xxx.py", line 61, in <module>
ValueError: invalid literal for int() with base 10: 'pipe_handle=632'
[25752] Failed to execute script 'xxx' due to unhandled exception!
绝了,还每个进程报一个错。查了一下,需要在if __name__ == '__main__':
的下面加这么一行:
# 略略略
if __name__ == '__main__':
multiprocessing.freeze_support() # 注意位置。加在代码开头一样会报错哦
# 略略略
这样多进程本身应该不会再造成error了。剩下的就看你写的代码的造化了。
3. 关于获取多进程执行函数的返回值
干过这种事吗👇
def func(c):
# 略略略
c.insert(返回值)
c = Container() # 名字瞎起的。里面可能有列表之类的变量
p1 = multiprocessing.Process(target=_func2, args=(c, ))
p1.start()
别这么干了,没用的。c
里空空如也。