Python 3.6+: Nested multiprocessing managers cause FileNotFoundError

2024/9/20 17:23:57

So I'm trying to use multiprocessing Manager on a dict of dicts, this was my initial try:

from multiprocessing import Process, Managerdef task(stat):test['z'] += 1test['y']['Y0'] += 5if __name__ == '__main__':test = Manager().dict({'x': {'X0': 10, 'X1': 20}, 'y': {'Y0': 0, 'Y1': 0}, 'z': 0})p = Process(target=task, args=(test,))p.start()p.join()print(test)

of course when I run this, the output is not what I expect, z updates correctly while y is unchanged! This is the output:

{'x': {'X0': 10, 'X1': 20}, 'y': {'Y0': 0, 'Y1': 0}, 'z': 1}

Then I googled, and found an explanation here, apparently the nested dicts have to also be Manager().dict()s rather than normal python dicts (possible since Python 3.6). So I did the following:

from multiprocessing import Process, Managerdef task(stat):test['z'] += 1test['y']['Y0'] += 5if __name__ == '__main__':test = Manager().dict({'x': Manager().dict({'X0': 10, 'X1': 20}), 'y': Manager().dict({'Y0': 0, 'Y1': 0}), 'z': 0})p = Process(target=task, args=(test,))p.start()p.join()print(test)print(test['y'])

But instead of it working properly, I get this unexplainable error(s), split to three parts for clarity. The first part corresponds to the test['y']['Y0'] += 5 while the second is simply the print(test) and the last is the output of print(test['y'])

Process Process-4:
Traceback (most recent call last):File "/usr/lib/python3.7/multiprocessing/process.py", line 297, in _bootstrapself.run()File "/usr/lib/python3.7/multiprocessing/process.py", line 99, in runself._target(*self._args, **self._kwargs)File "shit.py", line 5, in tasktest['y']['Y0'] += 5File "<string>", line 2, in __getitem__File "/usr/lib/python3.7/multiprocessing/managers.py", line 796, in _callmethodkind, result = conn.recv()File "/usr/lib/python3.7/multiprocessing/connection.py", line 251, in recvreturn _ForkingPickler.loads(buf.getbuffer())File "/usr/lib/python3.7/multiprocessing/managers.py", line 920, in RebuildProxyreturn func(token, serializer, incref=incref, **kwds)File "/usr/lib/python3.7/multiprocessing/managers.py", line 770, in __init__self._incref()File "/usr/lib/python3.7/multiprocessing/managers.py", line 824, in _increfconn = self._Client(self._token.address, authkey=self._authkey)File "/usr/lib/python3.7/multiprocessing/connection.py", line 492, in Clientc = SocketClient(address)File "/usr/lib/python3.7/multiprocessing/connection.py", line 619, in SocketClients.connect(address)
FileNotFoundError: [Errno 2] No such file or directory{'x': <DictProxy object, typeid 'dict' at 0x7f01de2c5860>, 'y': <DictProxy object, typeid 'dict' at 0x7f01de2c5898>, 'z': 1}Traceback (most recent call last):File "test.py", line 16, in <module>print(test['y'])File "<string>", line 2, in __getitem__File "/usr/lib/python3.7/multiprocessing/managers.py", line 796, in _callmethodkind, result = conn.recv()File "/usr/lib/python3.7/multiprocessing/connection.py", line 251, in recvreturn _ForkingPickler.loads(buf.getbuffer())File "/usr/lib/python3.7/multiprocessing/managers.py", line 920, in RebuildProxyreturn func(token, serializer, incref=incref, **kwds)File "/usr/lib/python3.7/multiprocessing/managers.py", line 770, in __init__self._incref()File "/usr/lib/python3.7/multiprocessing/managers.py", line 824, in _increfconn = self._Client(self._token.address, authkey=self._authkey)File "/usr/lib/python3.7/multiprocessing/connection.py", line 492, in Clientc = SocketClient(address)File "/usr/lib/python3.7/multiprocessing/connection.py", line 619, in SocketClients.connect(address)
FileNotFoundError: [Errno 2] No such file or directory

I'm not sure why this happens. The inner dicts evidently get created (as shown by the second part of the output). But for some reason, they cannot be read or written at all!. Why does this happen?

Extra: If I run the same python code through a python console (rather than a script) the error changes from FileNotFoundError to ConnectionRefusedError. But with the same exact traceback!

Answer

With Manager() in Manager().dict() you are starting a new manager-process each time, so you are really nesting managers (like the title says) and this is not the way it's supposed to be. What you need to do instead, is instantiate one Manager and then create dictionaries on that manager instance:

from multiprocessing import Process, Manager
from multiprocessing.managers import DictProxydef task(test):  # use parameter `test`, else you rely on forkingtest['z'] += 1test['y']['Y0'] += 5if __name__ == '__main__':with Manager() as m:test = m.dict({'x': m.dict({'X0': 10, 'X1': 20}),'y': m.dict({'Y0': 0, 'Y1': 0}),'z': 0})p = Process(target=task, args=(test,))p.start()p.join()print(test)print(test['y'])# convert to normal dict before closing manager for persistence# in parent or for printing dict behind proxiesd = {k: dict(v) if isinstance(v, DictProxy) else vfor k, v in test.items()}print(d) # Manager already closed here

Example Output:

{'x': <DictProxy object, typeid 'dict' at 0x7f98cdaaa588>, 'y': <DictProxy object, typeid 'dict' at 0x7f98cda99c50>, 'z': 1}
{'Y0': 5, 'Y1': 0}
{'x': {'X0': 10, 'X1': 20}, 'y': {'Y0': 5, 'Y1': 0}, 'z': 1}Process finished with exit code 0

You would also need to use Manager.Lock in case you plan to modify manager-objects from multiple processes.

https://en.xdnf.cn/q/72323.html

Related Q&A

Convert python disassembly from dis.dis back to codeobject

Is there any way to create code object from its disassembly acquired with dis.dis?For example, I compiled some code using co = compile(print("lol"), <string>, exec) and then printed di…

Loop over a tensor and apply function to each element

I want to loop over a tensor which contains a list of Int, and apply a function to each of the elements. In the function every element will get the value from a dict of python. I have tried the easy wa…

How to quickly get the last line from a .csv file over a network drive?

I store thousands of time series in .csv files on a network drive. Before I update the files, I first get the last line of the file to see the timestamp and then I update with data after that timestamp…

Force use of scientific style for basemap colorbar labels

String formatting can by used to specify scientific notation for matplotlib.basemap colorbar labels:cb = m.colorbar(cs, ax=ax1, format=%.4e)But then each label is scientifically notated with the base.I…

VS Code Doesnt Recognize Python Virtual Environment

Im using VS Code on a Mac to write Python code. Ive created a virtual environment named venv inside my project folder and opened VS Code in my project folder. I can see the venv folder in the Explore…

Why codecs.iterdecode() eats empty strings?

Why the following two decoding methods return different results?>>> import codecs >>> >>> data = [, , a, ] >>> list(codecs.iterdecode(data, utf-8)) [ua] >>>…

How to keep NaN in pivot table?

Looking to preserve NaN values when changing the shape of the dataframe.These two questions may be related:How to preserve NaN instead of filling with zeros in pivot table? How to make two NaN as NaN …

Using Pandas df.where on multiple columns produces unexpected NaN values

Given the DataFrameimport pandas as pddf = pd.DataFrame({transformed: [left, right, left, right],left_f: [1, 2, 3, 4],right_f: [10, 20, 30, 40],left_t: [-1, -2, -3, -4],right_t: [-10, -20, -30, -40], }…

Django star rating system and AJAX

I am trying to implement a star rating system on a Django site.Storing the ratings in my models is sorted, as is displaying the score on the page. But I want the users to be able to rate a page (from 1…

Create inheritance graphs/trees for Django templates

Is there any tool out there that would take a directory with a Django application, scan it for templates and draw/print/list a hierarchy of inheritance between templates?Seeing which blocks are being …