I am wondering which operations in Python
are guaranteed to be atomic in the presence
of multi-threading. In particular, are assignment
and reading of a dictionary entry atomic?
For example, initially:
dictionary = {}
dictionary[key] = old_value
Then thread 1 does:
v = dictionary[key]
And thread 2 does:
dictionary[key] = new_value2
And thread 3 does:
dictionary[key] = new_value3
What I want to make sure of is that
thread 1 will read either the old_value
for key, or new_value2, or new_value3,
but not an intermediate value.
Which value in particular does not matter to me, as that
obviously depends on timing. I just want to make sure
that the dictionary internal data structures can't
become corrupted by multiple writers / readers.
Note: I realize that in this particular case
I can use locks to guarantee safety, but I am
wondering whether the basic language operations
such as dictionary reads and updates are guaranteed
to be atomic.
A related, more general question, is which
Python operations are atomic, and which are not.
I was unable to find this in the language reference,
but please direct me to the correct location
if I missed it.
Thanks,
Glenn 8 3556
Glenn Kasten wrote: I am wondering which operations in Python are guaranteed to be atomic in the presence of multi-threading. In particular, are assignment and reading of a dictionary entry atomic?
[snip] I just want to make sure that the dictionary internal data structures can't become corrupted by multiple writers / readers.
[snip] Python operations are atomic, and which are not. I was unable to find this in the language reference, but please direct me to the correct location if I missed it.
It's probably not spelled out anywhere, but the "global interpreter
lock" entry and the Glossary and the first few paragraphs of section 8.1
of the documentation ("Thread State and the Global Interpreter Lock")
give you the gist of it.
Basically: multiple threads can't corrupt the interpreter's internals
(but a buggy C extension could).
-Dave
Dave Brueck wrote: Glenn Kasten wrote:
I am wondering which operations in Python are guaranteed to be atomic in the presence of multi-threading. In particular, are assignment and reading of a dictionary entry atomic?
[...] Basically: multiple threads can't corrupt the interpreter's internals (but a buggy C extension could).
The "dis" module can be helpful in analyzing such things, sometimes.
Realizing that the GIL ensures that individual bytecodes are
executed atomically ("boom!"), anything that shows up as a
separate bytecode instruction is basically thread-safe: def func():
.... v = dictionary[key]
.... def func2():
.... dictionary[key] = new_value2
.... dis.dis(func)
2 0 LOAD_GLOBAL 0 (dictionary)
3 LOAD_GLOBAL 1 (key)
6 BINARY_SUBSCR
7 STORE_FAST 0 (v)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE dis.dis(func2)
2 0 LOAD_GLOBAL 0 (new_value2)
3 LOAD_GLOBAL 1 (dictionary)
6 LOAD_GLOBAL 2 (key)
9 STORE_SUBSCR
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
The key instructions in the above are the dictionary lookup,
which is merely "BINARY_SUBSCR" in func(), and the dictionary
assignment, which is "STORE_SUBSCR" in func2(). If func
and func2 were in separate threads, either the lookup or
the store executes first, then the other, but they cannot
both be executing at the same time.
-Peter
Peter Hansen <pe***@engcorp.com> writes: Dave Brueck wrote:
Glenn Kasten wrote:
I am wondering which operations in Python are guaranteed to be atomic in the presence of multi-threading. In particular, are assignment and reading of a dictionary entry atomic? > [...] Basically: multiple threads can't corrupt the interpreter's internals (but a buggy C extension could).
[...]
The key instructions in the above are the dictionary lookup, which is merely "BINARY_SUBSCR" in func(), and the dictionary assignment, which is "STORE_SUBSCR" in func2(). If func and func2 were in separate threads, either the lookup or the store executes first, then the other, but they cannot both be executing at the same time.
As was pointed out to me when this came up recently, it is possible
for callbacks into python to screw this simple picture up a little.
The obvious case is a user-defined class with a __setitem__ method. In
this case, STORE_SUBSCR calls arbitrary Python code, and so can be
interrupted by a thread switch.
Given that the original question was about dictionaries, which are
coded in C (and so not subject to this issue) there is still the
following case: when the old value stored in the dictionary is
replaced, that could be the last reference to it. When the old value
is freed, its __del__ method gets called - arbitrary Python code
again.
But the basic idea is sound. The interpreter releases the GIL *only*
between Python bytecodes. As long as you cater for recursive cases
like the above (and obvious ones like CALL_METHOD), you're OK.
Finally, C code has the option of explicitly releasing the GIL -
"long-running" operations like file reads do this, but basic ops
don't.
Paul.
--
This signature intentionally left blank
Paul Moore wrote: Peter Hansen <pe***@engcorp.com> writes:
Dave Brueck wrote:
Glenn Kasten wrote:
I am wondering which operations in Python are guaranteed to be atomic in the presence of multi-threading. In particular, are assignment and reading of a dictionary entry atomic?
> [...]
Basically: multiple threads can't corrupt the interpreter's internals (but a buggy C extension could).
[...]
The key instructions in the above are the dictionary lookup, which is merely "BINARY_SUBSCR" in func(), and the dictionary assignment, which is "STORE_SUBSCR" in func2(). If func and func2 were in separate threads, either the lookup or the store executes first, then the other, but they cannot both be executing at the same time.
As was pointed out to me when this came up recently, it is possible for callbacks into python to screw this simple picture up a little.
The obvious case is a user-defined class with a __setitem__ method. In this case, STORE_SUBSCR calls arbitrary Python code, and so can be interrupted by a thread switch.
Given that the original question was about dictionaries, which are coded in C (and so not subject to this issue) there is still the following case: when the old value stored in the dictionary is replaced, that could be the last reference to it. When the old value is freed, its __del__ method gets called - arbitrary Python code again.
But the basic idea is sound. The interpreter releases the GIL *only* between Python bytecodes. As long as you cater for recursive cases like the above (and obvious ones like CALL_METHOD), you're OK.
Yep, though I think the OP was mostly concerned with Python's internals
gettin messed up by unlocked multithreaded access, so he doesn't have to
be concerned about the above.
-Dave
Paul Moore <pf******@yahoo.co.uk> wrote in news:y8**********@yahoo.co.uk: Given that the original question was about dictionaries, which are coded in C (and so not subject to this issue) there is still the following case: when the old value stored in the dictionary is replaced, that could be the last reference to it. When the old value is freed, its __del__ method gets called - arbitrary Python code again.
Right, but the new value has already been stored in the dictionary at the
point where the __del__ method is called, so as far as the OP is concerned
this is still safe.
Duncan Booth wrote: Paul Moore <pf******@yahoo.co.uk> wrote in news:y8**********@yahoo.co.uk: Given that the original question was about dictionaries, which are coded in C (and so not subject to this issue) there is still the following case: when the old value stored in the dictionary is replaced, that could be the last reference to it. When the old value is freed, its __del__ method gets called - arbitrary Python code again.
Right, but the new value has already been stored in the dictionary at the point where the __del__ method is called, so as far as the OP is concerned this is still safe.
For some definition of "safe", perhaps. It won't corrupt any Python
internals, but if the __del__() method has side effects that the
threaded code is relying on, it may give unexpected results. (One might
want to rely on the fact that, once an object holding a socket is
removed from a dictionary, that socket will be closed; if that close
happens in the object's __del__(), then there's no guarantee that it
*will* actually be closed before a thread switch occurs. (Relying on
__del__() is hazardous in any case, actually, thanks to differing GC
between different implementations of Python, but it's even worse in a
threaded environment.))
Jeff Shannon
Technician/Programmer
Credit International
Dave Brueck <da**@pythonapocrypha.com> writes: Yep, though I think the OP was mostly concerned with Python's internals gettin messed up by unlocked multithreaded access, so he doesn't have to be concerned about the above.
I don't think that Python's internals can *ever* be messed up by
unlocked multithreaded access - that's what the GIL is for.
Paul.
--
This signature intentionally left blank
Paul Moore wrote: Dave Brueck <da**@pythonapocrypha.com> writes:
Yep, though I think the OP was mostly concerned with Python's internals gettin messed up by unlocked multithreaded access, so he doesn't have to be concerned about the above.
I don't think that Python's internals can *ever* be messed up by unlocked multithreaded access - that's what the GIL is for.
Yeah, that was mentioned earlier:
"multiple threads can't corrupt the interpreter's internals (but a buggy
C extension could)."
-Dave This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Paul Moore |
last post by:
I can't find anything which spells this out in the manuals. I guess
that, at some level, the answer is "a single bytecode operation", but
I'm not sure that explains it for me.
This thought was...
|
by: Shayan |
last post by:
Is there a boolean flag that can be set atomically without needing to
wrap it in a mutex? This flag will be checked constantly by multiple
threads so I don't really want to deal with the overhead...
|
by: dm |
last post by:
Hi,
I'd like to know if the C standard can guarantee that an assignment to/from
a variable will be atomic, that is will occur in a single indivisible
instruction.
For example, if I have the...
|
by: robert |
last post by:
In very rare cases a program crashes (hard to reproduce) :
* several threads work on an object tree with dict's etc. in it. Items
are added, deleted, iteration over .keys() ... ). The threads are...
|
by: blackstreetcat |
last post by:
consider this code :
int i; //gobal var
Thread1:
i=some value;
Thread2:
if (i==2) dosomething();
else dosomethingelse();
|
by: Dave Stallard |
last post by:
Pardon if this is the wrong newsgroup for this question, and/or if this
question is naive.
I have a multi-threaded Windows application in which certain
variables/object fields are shared: one...
|
by: japhy |
last post by:
Is there a way to read a line (a series of characters ending in a
newline) from a file (either by descriptor or stream) atomically,
without buffering additional contents of the file?
|
by: Freedom fighter |
last post by:
Hello,
Is a singleton class the same as an atomic class? I know that a singleton class
can only be instantiated once, but does that concept apply to an atomic class?
Thank you.
|
by: Jon Harrop |
last post by:
Can read locks on a data structure be removed safely when updates are
limited to replacing a reference? In other words, is setting a reference an
atomic operation?
I have been assuming that all...
|
by: taylorcarr |
last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: aa123db |
last post by:
Variable and constants
Use var or let for variables and const fror constants.
Var foo ='bar';
Let foo ='bar';const baz ='bar';
Functions
function $name$ ($parameters$) {
}
...
|
by: ryjfgjl |
last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
|
by: BarryA |
last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
|
by: Hystou |
last post by:
There are some requirements for setting up RAID:
1. The motherboard and BIOS support RAID configuration.
2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
by: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
| |