Is operation like a,b=1,2
atomic ?
Some background of my issue :I am working with signal . which are being raised from some external process. Here i want to avoid the cases when signal is being captured between setting a=1 and b=2
. Is there any way to achieve this ?
Is there any way to check if given step is atomic or not ?
Although some operations are atomic in Python, we should never rely on an operation being atomic. There are a number of good reasons for this, such as: The operations may not be atomic if the code is executed by a different Python interpreter. The behavior of the reference Python interpreter may change in the future.
So the assignment is a single python bytecode (instruction 2), which is atomic in CPython since it executes one bytecode at a time. += corresponds to 4 instructions, which is not atomic.
It is not atomic because it takes multiple bytecode instructions to assign to multiple names and it doesn't take long to confirm it experimentally:
import signal
a = 1
b = 2
def handler(sig, trace):
print a, b
def main():
global a, b
signal.signal(signal.SIGINT, handler)
while True:
a, b = 3, 4
a, b = 1, 2
if __name__ == '__main__':
main()
$ python atom.py
^C3 4
^C3 4
^C1 2
^C1 2
^C3 4
^C1 2
^C1 2
^C1 2
^C1 2
^C1 4 <<<< inconsistent state
In this particular case, if you want two values to change atomically, you can get away with assignment to tuple and accessing its elements in the signal handler. Looking at disassembly:
>>> a = 1
>>> b = 2
>>> c = (1, 2)
>>> def foo():
... global a, b
... a, b = 1, 2
...
>>> def bar():
... global c
... c = (1, 2)
...
>>> dis.dis(foo)
3 0 LOAD_CONST 3 ((1, 2))
3 UNPACK_SEQUENCE 2
6 STORE_GLOBAL 0 (a)
9 STORE_GLOBAL 1 (b)
12 LOAD_CONST 0 (None)
15 RETURN_VALUE
>>> dis.dis(bar)
3 0 LOAD_CONST 3 ((1, 2))
3 STORE_GLOBAL 0 (c)
6 LOAD_CONST 0 (None)
9 RETURN_VALUE
No matter how complex the value is, assignment to a variable (or dict
entry, or object field) is a single atomic store operation.
No, the sequence assignment is not atomic. Just take a look at the byte code:
>>> def unpack():
a,b=1,2
>>> import dis
>>> dis.dis(unpack)
2 0 LOAD_CONST 3 ((1, 2))
3 UNPACK_SEQUENCE 2
6 STORE_FAST 0 (a)
9 STORE_FAST 1 (b)
12 LOAD_CONST 0 (None)
15 RETURN_VALUE
The assignment takes multiple opcodes to evaluate the tuple and store the result in variables.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With