I was wondering about the equivalent of Java's "volatile", and found this answer.
An equivalent to Java volatile in Python
Which (basically) says that everything is effectively volatile in python, at least in cpython, because of the GIL. Which makes sense, everything is locked by the GIL, no memory barriers to worry about, etc. But I would be happier if this were documented and guaranteed by specification, rather than have it be a result of the way that cpython happens to currently be implemented.
Because, say I want one thread to post data and others to read it, so I can choose something like this:
class XFaster:
def __init__(self):
self._x = 0
def set_x(self, x):
self._x = x
def get_x(self, x):
return self._x
class XSafer:
def __init__(self):
self._x = 0
self._lock = threading.Lock()
def set_x(self, x):
with self._lock:
self._x = x
def get_x(self, x):
with self._lock:
return self._x
I'd rather go with XFaster
or even not use a getter and setter at all. But I also want to do things reliably and "correctly". Is there some official documentation that says this is OK? What about say putting a value in a dict
or appending to a list
?
In other words, is there a systematic, documented way of determining what I can do without a threading.Lock
(without digging through dis
or anything like that)? And also preferably in a way that won't break with a future python release.
On edit: I appreciate the informed discussion in comments. But what I would really want is some specification that guarantees the following:
If I execute something like this:
# in the beginning
x.a == foo
# then two threads start
# thread 1:
x.a = bar
# thread 2
do_something_with(x.a)
I want to be sure that:
- when thread 2 reads
x.a
it reads eitherfoo
orbar
- if the read in thread 2 occurs physically later than the assignment in thread 1, then it actually reads
bar
Here are some things I want not to happen:
- the threads get scheduled on different processors, and the assignment
x.a=bar
from thread 1 isn't visible to the thread 2 x.__dict__
is in the middle of being re-hashed and so thread 2 reads garbage- etc
list
s are, for example, butqueue
s are. Generally, accessing is thread safe, but setting is not. If you need to set something, grab the lock before setting then release. This is what actually makes setting safe. – Henceatomic_store()
from stdatomic.h, so concurrent write + read of the same object could trigger data-race UB in the interpreter. – Slidingvolatile
and memory-barriers had me thinking about lock-free atomics, which would probably require a huge overhaul of the internals of any current Python implementation, or a new one from the ground up. Ok, so software-visiblethreading.Lock()
in Python only exists for higher-level things that take multiple Python statements to do. If the CPython interpreter is single-threaded, there's no concurrency? Or does Python threading exist for other Python implementations like Cython or PyPy to use? – Sliding[memory-barriers]
tag :P – Slidinga,b=c,d
a single statement?). But also, just because they don't happen at once doesn't automatically imply that the memory that thread A sees will reflect everything that happened in thread B, say if the os schedules the threads on different processors. It should, and almost certainly does work that way, but it would be nice if there were some documentation on python.org that said this explicitly. – Elizabetelizabethx.a=bar
is not one well-defined operation – it is syntactic sugar for a method call that may run arbitrary code, including arbitrary many bytecode instructions or thread/process/task synchronisation operation. Seeproperty
andobject.__setattr__
for the most obvious causes of non-atomicity. – Nastyx.a=5
does actually is it looks up the key "a" in the hash tablex.__dict__
and places the value5
there. And so whilex.a=5
seems like it should be atomic, updating a hash table is not the sort of thing one generally assumes is automatically going to be atomic and thread-safe. – Elizabetelizabethset_x
from one thread andget_x
from other threads usingXFaster
or do I need to useXSafer
to make sure that I don't run into any problems. And also I would like to read about this on python.org, not on some blog post. – ElizabetelizabethXFaster
class above would definitely not be safe. But the GIL alone doesn't guarantee that it is safe. – Elizabetelizabeth