-1

Should I use atomic counter with Locking or can I use this?

 def somefunc(someparam):
     if someparam:
        dic['key'] +=1
zanseb
  • 1,275
  • 10
  • 20
oshaiken
  • 2,593
  • 1
  • 15
  • 25

2 Answers2

3

No, your code is not threadsafe, because using an += augmented assignment on a dictionary value takes 3 opcodes to execute:

>>> dis.dis(compile("dic['key'] += 1", '', 'exec'))
  1           0 LOAD_NAME                0 (dic)
              3 LOAD_CONST               0 ('key')
              6 DUP_TOPX                 2
              9 BINARY_SUBSCR
             10 LOAD_CONST               1 (1)
             13 INPLACE_ADD
             14 ROT_THREE
             15 STORE_SUBSCR
             16 LOAD_CONST               2 (None)
             19 RETURN_VALUE

The opcode at position 9, BINARY_SUBSCR retrieves the current value from the dictionary. Anywhere between opcodes 9 and 15 (where STORE_SUBSCR puts the value back in), a thread-switch could take place and a different thread could have updated the dictionary.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thanks! Thats all I needed to know, I knew that dic are thread safe, but I was not sure about += – oshaiken Nov 14 '16 at 17:04
  • @OlzhasShaikenov: dictionaries are not necessarily thread-safe; if the object you are storing is an instance of a Python-defined class with `__hash__` and / or `__eq__` defined, then those methods will be executed by the interpreter when storing the object and a thread context switch can take place. – Martijn Pieters Nov 14 '16 at 17:07
  • This does not gel with what I have come to understand about the GIL and its purpose _at all_ from general reading. Is its purpose then to make a single opcode threadsafe? Is there something specific I could search to understand the GIL in this context? – roganjosh Mar 03 '17 at 20:25
  • 1
    @roganjosh yes, the GIL is there to ensure each opcode is processed in its entirety, leaving the evaluation loop free to make changes to the interpreter state without fear of race conditions. The [Python C API has some information](https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock); follow the links from there. – Martijn Pieters Mar 03 '17 at 22:31
1

Python's built-in structures are thread safe for single operations. The GIL (global interpreter lock) takes care of that. But it is mostly difficult to see where a statement becomes more operations.

Adding a lock will give you peace of mind:

def somefunc(someparam):
    if someparam:
        with lock:
            dic['key'] +=1
zanseb
  • 1,275
  • 10
  • 20
  • 1
    Thanks, I knew that I can use a lock. Question was if that specific operation was thread-safe, http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm – oshaiken Nov 14 '16 at 17:24