A plain Python object is one that has implemented in Python, doesn’t subclass any builtin classes (other than object) and doesn’t implement __getattribute__/__setattr__.
In other words, “normal” attribute access.
We need to be very specific here. I assume we mean attributes backed by plain old __dict__ and for now exclude attributes implemented via descriptors such as @property and __slots__. (@property maybe difficult or probably next to impossible. But I think __slots__ might be doable?)
Agreed, and even simpler obj.a = 12 will need to decref the former value referenced from obj.a and thus may run a finalizer which being a function call means it can be a premption point. Thus:
obj.a = 12
assert obj.a == 12
may fail. So while assignment may be atomic it is not necessarily preemption free and the very next statement may witness a world which had changed in unexpected ways be another GIL thread running between the two statements.
yes, sorry “exact int” was meant to be an example, but was worded poorly. My “model” says that compound operations are only GIL atomic for a small subset of exact builtin types such as numerics.
In terms of FT goal being SC that is great, but unless I’ve missed something the FT impl currently defaults to RA for stores/loads.
Regarding my “simple enough for devs to reason about”. I agree, my framing was from a Java dev used to the Java memory model. I agree that these types of memory modes are still hard to reason about and your PEP-805 is ultimately a better direction for ease of understanding.
Since at least java 8, the requirements for the language have been significantly stronger (more restrictive on implementations) than python ever has. Some of the way this has been discussed in this and parallel discussions has been including assumptions that are already implementation specific, whether that be that “operation” isn’t even something required to be the same across implementations, to that half of the questions posed originally were specifically referencing the GIL, something that is a planned to be phased out implementation detail of one specific implementation.
I get the desire for stronger language, I argue for it myself where I would benefit from it, but I think it’s a disservice to those discussing it to start with a framing that’s incompatible with being about the language and not expressly limit the scope to what the discussion can be compatible with. In this case, if we’re talking about the guarantees provided by the GIL, that’s never going to be language specification, but could be a useful set of documented guarantees for the GIL-enabled build of CPython.
I read the OP as taking a wider view, and using the GIL/free-threading builds as a first step to have something concrete to talk about (and even if the outcome doesn’t become a language guarantee, having those concurrency models be documented would also be valuable just for CPython itself).
In my opinion I don’t think there’ll ever been a single memory model for the Python language beyond mentioning it as implementation-defined behavior, and that “each implementation that supports multithreading shall document a memory model (or memory models as appropriate) :
- What built-in objects and operations give what kind of concurrency behavior (atomic or otherwise)
- What kind of memory ordering (sequential consistency / release-acquire etc.) is provided by the implementation
- How garbage collection / reference counting / finalization behaves in that implementation when multithreading is involved, etc.
- Whether the implementation makes any guarantee on the above behavior.”
The above discussions can very well serve as a starting point for CPython-GIL and CPython-FT. Other implementations shall be free to choose whether and how closely to follow CPython-(GIL/FT).
I’d go at list a bit further. The language could prescribe a basic model which can be relied upon across implementations. This basic model would unfortunately likely need to be quite weak so as not to force implementations down paths which they don’t fit. Each implementation could then define a stronger model. I’d only do this out of practicality and in fact did do that for the thread-sanitizer I’m working on.
| Aspect | weak |
|---|---|
| Ordinary accesses | No implicit cross-thread ordering or publication guarantees. |
| Native storage | Built-in operations retain their promised structural safety; universal serialization is not assumed. Unreviewed native sharing may still be flagged. |
| Concurrency | Full parallelism is allowed. |
| Synchronization | Releasing a lock happens-before a subsequent successful acquisition of that lock. Other recognized explicit synchronization and thread lifecycle handoffs also establish happens-before. |
| Compound operations | Not implicitly atomic. Lost updates, check-then-act races, inconsistent snapshots, and write skew remain possible. |
| Data races | Unordered read/write and write/write conflicts are reportable; read/read pairs are not. |
Off-topic for this thread but since you’re bringing it up: I’d love to hear more about this thread sanitizer you’re working on. How do you avoid false positives for detecting races?
Hi Nathan,
The thread-sanitizer was started by a grad student last year as part of their master’s thesis, see PyTsan: Automated Data Race Detection in Python Programs . I’ve taken on the work now to change it form something academically interesting into something that can be used for real. My version which I intend to eventually make public adds support for the gil/ft models and a large number of other types of thread-safety risk detections such as deadlocks, check then act bugs, etc. For the most part it is “false positive” free as it flags places where it witnesses the same storage location being accessed across multiple threads without any happens-before relationship. Potential for deadlock is based on witnessing lock inversion over time even if never simultaneously, i.e. we don’t have to deadlock to detect a deadlock risk.
Thank you for linking the thesis, I hadn’t heard about it. This seems really potentially useful! I’m eagerly waiting to hear more about this.