A viable solution for Python concurrency
A viable solution for Python concurrency
Posted Oct 14, 2021 19:21 UTC (Thu) by NYKevin (subscriber, #129325)In reply to: A viable solution for Python concurrency by chris_se
Parent article: A viable solution for Python concurrency
This is not limited to C extensions. Consider for example:
>>> def foo(l, x):
... l += [x]
...
>>> dis.dis(foo)
2 0 LOAD_FAST 0 (l)
2 LOAD_FAST 1 (x)
4 BUILD_LIST 1
6 INPLACE_ADD
8 STORE_FAST 0 (l)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
Assuming that l is a list, this function atomically appends x to it. We know that it must be atomic, because INPLACE_ADD is a single bytecode instruction, the GIL must be held for the entire execution of that instruction, and lists are implemented in C, so this instruction does not create an additional stackframe of Python bytecode. The STORE_FAST is a red herring; it just rebinds a local variable in a scope which we immediately destroy (so the interpreter could have optimized it out without altering the semantics of the function).
The problem is that I don't see a reasonable way to preserve that atomicity:
- Automatic fine-grained locking would slow down the single-threaded case.
- Automatic smart fine-grained locking, where the list is only locked if it's shared by multiple threads, is less likely to help than you might expect, because Python has a lot of shared mutable dictionaries in its internal implementation (basically, every scope is a dict or dict-like-thing), which are subject to the same problem. So you still end up with a lot of unnecessary (or "probably" unnecessary) locking in the multi-threaded case.
- You could do some kind of lock-free data structure, but this is a general problem affecting dicts, lists, sets, and probably other data structures as well. It would require a lot of work and complexity, and I'm not even sure if every instance of this problem is solvable that way.