3 ms·
Two different kinds of concurrency, a twist! If you have a link to enlighten, I'd love to read more about this.
by verdagon 5y ago
Two different kinds of concurrency, a twist! If you have a link to enlighten, I'd love to read more about this.
- Kranar 5y agoThe precise definition of a concurrent access is with respect to a programming language's memory model. Now Python does not provide formal semantics for its memory model (neither does Rust for that matter or C++ prior to C++11), instead Python is defined by its reference implementation where individual reads and writes are protected by the GIL. So while threads in Python run concurrently as in individual operations interleave with one another, there is never a concurrent read or write operation. Every individual operation performed by the Python bytecode interpreter is protected by the GIL, ie. atomic. That said, reads and writes can be atomic and still subject to race conditions which is what your example demonstrates. All your article shows is that data race freedom does not imply race condition freedom and this true not only of Python but of all programming languages.
- verdagon 5y agoTwo operations can be concurrent, even if they are run on the same thread, as long as they are unsequenced, in other words, there is nothing making one happen before the other. That's what the C++ standard says, linked from the wikipedia article you linked. I realize that C++ may not be completely applicable to Python, but this fits my prior understanding of the topic. Since there's no formal semantics to consult here, no actual alternate definition of concurrency, and the definition of data race fits, I can't say that the article is incorrect. This is going long and I need to get dinner, but thank you for the great discussion!
- Kranar 5y agoYou have misread what C++/Wikipedia says and are hence incorrect. The Wikipedia article says that actions are potentially concurrent if (they run from two different threads) OR (they are unsequenced AND one operation is performed by a signal handler). I have added the parenthesis to group together the logical clauses. Your omission of the requirement that the operation be performed from within a signal handler is significant and Wikipedia states the following about it: "The parts of this definition relating to signal handlers are idiosyncratic to C++ and are not typical of definitions of data race." Now we can definitely go into the nature of signal handlers in C++, but suffice it to say signal handlers are not considered to be executed from within the same thread as the main program. A signal handler is executed from within a special execution context that is independent of the rest of the program and whose behavior is distinct from typical threads. Suffice to say, other than specific idiosyncrasies, a signal handler is treated as if it were a separate thread of execution (even though technically an implementation does not have to actually spawn a separate thread for a signal handler).
- mirashii 5y agoThere's plenty of reading in the set of links in the grandparent, so maybe I can just quickly clarify. When we speak of concurrency and data races, we're speaking about concurrent accesses to a particular memory location, where concurrent means "at the same or overlapping times". In Python at this level, we don't even have a notion of a memory address. In fact, the memory address of where the integer itself is stored is going to be different, since integers in Python are boxed and immutable. Even if that weren't the case and these were direct memory accesses as you'd see in a lower level language, this would still not be able to introduce a data race, as the GIL prevents these two threads from ever actually running at the same time (while executing pure-python code that does not otherwise release the GIL. A poorly written extension or buggy code outside the GIL could cause data races, but that's a bit of a rabbithole). They'll hop back and forth as they acquire/release the GIL, and so the memory accesses can never race.
- verdagon 5y agoI'm not seeing anything in the links suggesting that there's a special different "concurrency" than the one commonly used in programming discussion. The Wikipedia article quotes part of the C++ standard which defines "potentially concurrent", but even with that definition, the article's understanding of data race stands, because these two operations are indeed unsequenced w.r.t. each other. I don't see a reason to depart from the usual understanding of "concurrent", but I'm open to being convinced!
- mirashii 5y agoLet's try simpler: No code that runs under the GIL is ever run concurrently. All of the code in the example holds the GIL, there's never any concurrency in your article! With no concurrency, there can be no data race.