多处理管理器在 pool.apply_async 的非常简单的示例上失败
Multiprocessing Manager failing on very simple example with pool.apply_async
我在我的代码中看到一些与 python multiprocessing
相关的意外行为,尤其是 Manager
class。我写了一个超级简单的例子来尝试更好地理解发生了什么:
import multiprocessing as mp
from collections import defaultdict
def process(d):
print('doing the process')
d['a'] = []
d['a'].append(1)
d['a'].append(2)
def main():
pool = mp.Pool(mp.cpu_count())
with mp.Manager() as manager:
d = manager.dict({'c': 2})
result = pool.apply_async(process, args=(d))
print(result.get())
pool.close()
pool.join()
print(d)
if __name__ == '__main__':
main()
这失败了,从 result.get()
打印的堆栈跟踪如下:
multiprocessing.pool.RemoteTraceback:
"""
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/multiprocessing/pool.py", line 121, in worker
result = (True, func(*args, **kwds))
File "<string>", line 2, in __iter__
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/multiprocessing/managers.py", line 825, in _callmethod
proxytype = self._manager._registry[token.typeid][-1]
AttributeError: 'NoneType' object has no attribute '_registry'
"""
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "mp_test.py", line 34, in <module>
main()
File "mp_test.py", line 25, in main
print(result.get())
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/multiprocessing/pool.py", line 657, in get
raise self._value
AttributeError: 'NoneType' object has no attribute '_registry'
我仍然不清楚这里发生了什么。在我看来,这似乎是管理器 class 的一个非常非常直接的应用程序。它几乎是实际 example used in the official python documentation 的副本,唯一的区别是我使用的是一个池并且 运行 使用 apply_async 来处理这个过程。我这样做是因为那是我在实际项目中使用的。
澄清一下,如果我没有 result =
和 print(result.get())
,我就不会得到堆栈跟踪。当我 运行 脚本时,我只看到 {'c': 2}
打印出来,这向我表明出现了问题并且没有显示出来。
有几件事要开始:首先,这不是您 运行 的代码。您发布的代码有
result = pool.apply_async(process2, args=(d))
但是没有process2()
定义。假设“过程”是有意的,接下来是
args=(d)
部分。这与键入
相同
args=d
但这不是需要的。您需要传递一系列预期参数。所以你需要将该部分更改为
args=(d,) # build a 1-tuple
或
args=[d] # build a list
然后输出变为
{'c': 2, 'a': []}
为什么 'a' 列表中没有 1 和 2?因为只有字典本身存在于管理器服务器上。
d['a'].append(1)
首先从服务器获取'a'的映射,这是一个空列表。但是那个空列表不会以任何方式共享 - 它是 process()
的本地列表。您将 1 添加到它,然后它被丢弃 - 服务器对此一无所知。 2 也一样。
要得到你想要的,你需要“做点什么”来告诉管理器服务器你改变了什么;例如,
d['a'] = L = []
L.append(1)
L.append(2)
d['a'] = L
我在我的代码中看到一些与 python multiprocessing
相关的意外行为,尤其是 Manager
class。我写了一个超级简单的例子来尝试更好地理解发生了什么:
import multiprocessing as mp
from collections import defaultdict
def process(d):
print('doing the process')
d['a'] = []
d['a'].append(1)
d['a'].append(2)
def main():
pool = mp.Pool(mp.cpu_count())
with mp.Manager() as manager:
d = manager.dict({'c': 2})
result = pool.apply_async(process, args=(d))
print(result.get())
pool.close()
pool.join()
print(d)
if __name__ == '__main__':
main()
这失败了,从 result.get()
打印的堆栈跟踪如下:
multiprocessing.pool.RemoteTraceback:
"""
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/multiprocessing/pool.py", line 121, in worker
result = (True, func(*args, **kwds))
File "<string>", line 2, in __iter__
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/multiprocessing/managers.py", line 825, in _callmethod
proxytype = self._manager._registry[token.typeid][-1]
AttributeError: 'NoneType' object has no attribute '_registry'
"""
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "mp_test.py", line 34, in <module>
main()
File "mp_test.py", line 25, in main
print(result.get())
File "/usr/local/Cellar/python/3.7.5/Frameworks/Python.framework/Versions/3.7/lib/python3.7/multiprocessing/pool.py", line 657, in get
raise self._value
AttributeError: 'NoneType' object has no attribute '_registry'
我仍然不清楚这里发生了什么。在我看来,这似乎是管理器 class 的一个非常非常直接的应用程序。它几乎是实际 example used in the official python documentation 的副本,唯一的区别是我使用的是一个池并且 运行 使用 apply_async 来处理这个过程。我这样做是因为那是我在实际项目中使用的。
澄清一下,如果我没有 result =
和 print(result.get())
,我就不会得到堆栈跟踪。当我 运行 脚本时,我只看到 {'c': 2}
打印出来,这向我表明出现了问题并且没有显示出来。
有几件事要开始:首先,这不是您 运行 的代码。您发布的代码有
result = pool.apply_async(process2, args=(d))
但是没有process2()
定义。假设“过程”是有意的,接下来是
args=(d)
部分。这与键入
相同args=d
但这不是需要的。您需要传递一系列预期参数。所以你需要将该部分更改为
args=(d,) # build a 1-tuple
或
args=[d] # build a list
然后输出变为
{'c': 2, 'a': []}
为什么 'a' 列表中没有 1 和 2?因为只有字典本身存在于管理器服务器上。
d['a'].append(1)
首先从服务器获取'a'的映射,这是一个空列表。但是那个空列表不会以任何方式共享 - 它是 process()
的本地列表。您将 1 添加到它,然后它被丢弃 - 服务器对此一无所知。 2 也一样。
要得到你想要的,你需要“做点什么”来告诉管理器服务器你改变了什么;例如,
d['a'] = L = []
L.append(1)
L.append(2)
d['a'] = L