在Windows上的Python 3.5中,我试图设计一些多处理代码,这些代码需要一些预处理变量才能用于输入的函数。
为了使这些变量可用,我将它们视为全局变量。
虽然这是以非并行方法工作的,但使用multiprocessing.Pool
会显示如果从初始化以来从未修改过全局会发生的行为。
请考虑以下代码段:
from multiprocessing import Pool
testlist = []
def f(x):
return x*x + testlist[0]
def main():
global testlist
input_iter = range(10)
testlist = [1, 2, 3, 4, 5]
for i in input_iter:
print(f(i))
with Pool(2) as pool:
for i in pool.imap_unordered(f, input_iter):
print(i)
if __name__ == '__main__':
main()
函数f(x)
简单地对输入求平方,并添加全局变量testlist
中的元素。 testlist
首先全局定义为空列表,然后进行修改以包含[1, 2, 3, 4, 5]
函数中的列表main()
。
运行此代码将为简单的for
循环生成所需的输出,但多处理循环将向IndexError
工作者抛出Pool
:testlist
变量尚未修改为包含值,仍然是一个空列表。
1
2
5
10
17
26
37
50
65
82
multiprocessing.pool.RemoteTraceback:
"""
Traceback (most recent call last):
File "\lib\multiprocessing\pool.py", line 119, in worker
result = (True, func(*args, **kwds))
File "progresstest.py", line 7, in f
return x*x + testlist[0]
IndexError: list index out of range
"""
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "progresstest.py", line 21, in <module>
main()
File "progresstest.py", line 17, in main
for i in pool.imap_unordered(f, input_iter):
File "\lib\multiprocessing\pool.py", line 695, in next
raise value
IndexError: list index out of range
在创建Pool
个worker之前修改全局变量,而简单循环显示此赋值有效:IndexError
循环中没有抛出for
。我知道状态不能在进程之间共享,但是这个变量是在并行执行之前定义的,不会改变。
为什么会这样?
答案 0 :(得分:2)
在类UNIX操作系统上,multiprocessing
(默认情况下)使用fork
系统调用创建Pool
以制作一个或多个完全副本主过程。
在ms-windows上,没有fork
系统调用,因此multiprocessing
的工作方式不同。它启动一个新的Python进程,将原始程序作为模块导入。在这种情况下,系统不会调用main()
,因此您的全局信息不会更新。
答案 1 :(得分:0)
我会将要传递的值包装在元组中(如Roland所建议的那样),或者包装在可能提供更灵活处理方式的列表中。这是带有(嵌套)列表的示例:
import multiprocessing
import os
from time import sleep
def foo(transptbox):
[myvalues,a] = transptbox
for j in myvalues:
val1, val2, val3, val4, val5 = j
a = a*a + val1 # stands for your process with iterable a and value 1
sleep(0.1) # using sleep to simulate processing time long enough to activate multiprocessing
print(f"Process-ID {os.getpid()}:{a} : {val1} {val2} {val3} {val4} {val5}") # just to show values are available
return a
if __name__ == '__main__':
values_to_be_sent = [[1,2,3,4,5]]
input_iter = range(10)
tbox =[[0 for y in range(2)]for x in range(len(input_iter))]
for x in range(len(input_iter)):
tbox[x] = [values_to_be_sent, input_iter[x]]
pool = multiprocessing.Pool(processes = 3)
result = list(pool.map(foo, tbox))
print(result)
输出是您想要的结果:
C:\Users\757\PycharmProjects\exu\venv\Scripts\python.exe C:/Users/757/.PyCharmCE2018.1/config/scratches/scratch_9.py
Process-ID 3476:1 : 1 2 3 4 5
Process-ID 4416:5 : 1 2 3 4 5
Process-ID 5568:2 : 1 2 3 4 5
Process-ID 3476:10 : 1 2 3 4 5
Process-ID 4416:17 : 1 2 3 4 5
Process-ID 5568:26 : 1 2 3 4 5
Process-ID 3476:37 : 1 2 3 4 5
Process-ID 5568:50 : 1 2 3 4 5
Process-ID 4416:65 : 1 2 3 4 5
Process-ID 3476:82 : 1 2 3 4 5
[1, 2, 5, 10, 17, 26, 37, 50, 65, 82]
Process finished with exit code 0