-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
get_lock() method is not present for Values created using multiprocessing.Manager() #79967
Comments
According to the documentation of the multiprocessing.Value() class available here https://docs.python.org/3.6/library/multiprocessing.html#multiprocessing.Value Operations like += which involve a read and write are not atomic. So if, for instance, you want to atomically increment a shared value it is insufficient to just do counter.value += 1 with counter.get_lock():
counter.value += 1 What happens is that when running the following snippet import multiprocessing
manager = multiprocessing.Manager()
value = manager.Value('i', 0)
value.get_lock() the result is |
You are not using multiprocessing.Value: >>> import multiprocessing
>>> x = multiprocessing.Value("i", 0)
>>> x.get_lock()
<RLock(None, 0)> |
Nothing in the documentation says that multiprocessing.Value and the object returned by manager.Value() is any different. Nor is it clear why they should be. It is perfectly understandable to expect that manager.Value() is actually of type multiprocessing.Value. It is also a valid assumption that the "canonical" way to acquire such objects are from a Manager, not directly. An example that reinforces this assumption is that of the Queue class, which HAS to be created through a Manager, lest we get "RuntimeError: Queue objects should only be shared between processes through inheritance". In conclusion, I think this is definitely a valid issue. What I am not so sure about is if it is (just) an issue in the documentation or the API itself. |
OK, actually: trying to create a multiprocessing.Value object and sharing it between a Pool of processes results in "RuntimeError: Synchronized objects should only be shared between processes through inheritance". So the only way seems to be through a Manager, but its Value() is of a different class? |
Reading the docs, I'd definitely expect multiprocessing.Manager().Value to obey the same interface as multiprocessing.Value. The SyncManager docs say:
It does also say (under the linked definition for Proxy Objects):
which implies the proxy might be more limited, but in fact the proxy is wrapping a completely different underlying class, multiprocessing.managers.Value (that has nothing to do with the class you'd get from calling multiprocessing.Value or multiprocessing.sharedctypes.Value). It looks like there was, at some point, an attempt to make certain interfaces match; multiprocessing.managers.Value's initializer has a prototype of: def __init__(self, typecode, value, lock=True): (documented prototype excludes the lock argument), but AFAICT, lock is completely ignored, and typecode is stored as _typecode on the underlying Value, but otherwise ignored; the multiprocessing.managers.ValueProxy object returned by manager.Value() doesn't expose it (except insofar as you can call ._getvalue() on it to retrieve a copy of the underlying Value), and even if you get the unwrapped object, all _typecode does is change the repr; it's not used anywhere else. It seems like SyncManager.Value is just the worst of all possible worlds; it has a prototype that (roughly) matches multiprocessing.Value/multiprocessing.sharedctypes.Value, and the limited documentation implies it serves the same function, but:
I'm not sure what to do about it though; the manager version of Value is much more flexible, and I'm sure there is existing code that takes advantage of that, so we can't rewrite to make it ctypes backed. The multiprocessing.managers code is too new/complex for me to determine if any easy solution exists to expand multiprocessing.managers.ValueProxy to support context management/get_lock/get_obj to match the behavior of the class returned by multiprocessing.Value/multiprocessing.sharedctypes.Value, but it seems like, if we're going to let the docs imply a relationship, we ought to at least try to make the API of the two classes roughly match. |
What's being done about this? There is also not an obvious temporary work-around. |
Are there any proposed solutions to this problem or any workaround aside from using an additional SyncManager.Lock object to synchronize access to a SyncManager.Value? |
This issue is still present since 2019, also just encountered this. I guess I will have to stick with additional Lock, but I welcome any updates on this. |
I just ran into this as well (expected |
I've just encountered the same problem. I guess the main issue that the description of It's nothing but my assumption and guess. I would ask the maintainers to describe this class in the documentation. Because right now there is even no mention of the |
Ran into this as well. Surprised to find such a sharp corner in multiprocessing. Since Experienced the issue in Python 3.9 |
Just ran into this as well while trying to increment a |
How is this issue still open? I am facing the same problem in Python 3.11.8.
|
I ran into the same issue with Python 3.12.4
|
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: