Search code examples
pythonpython-multithreading

Do I need synchronization for immutable objects?


I have an immutable object (a float) that is "written" by one thread and read by another one. Do I need synchronization for that?

class Foo:
   def __init(self):
      self._bar = None

   def writeAttribute(self, newValue):
      self._bar = newValue

   def readAttribute(self):
      return self._bar

Note that writeAttribute and readAttribute are called from different threads for the same instance. My understanding is that readAttribute returns a "reference" either to the old value or the new one, but nothing in between.


Solution

  • In CPython (the one from python.org) the Global Interpreter Lock ("GIL") ensures that only one thread at a time is executing Python bytecodes. Also, threads can be preempted in between bytecodes, but not "inside" them. That means bytecodes are atomic.

    That means that every action that takes a single bytecode is thread-safe as a side-effect of the GIL.

    Consider the following code, were the dis module is used to see bytecodes for a function:

    
    In [2]: bar = 3.14
    Out[2]: 3.14
    
    In [3]: def modify(new):
       ...:     global bar
       ...:     bar = new
       ...:     
    
    In [4]: dis.dis(modify)
      3           0 LOAD_FAST                0 (new)
                  2 STORE_GLOBAL             0 (bar)
                  4 LOAD_CONST               0 (None)
                  6 RETURN_VALUE
    

    Assigning a new value to the global bar takes only a single STORE_GLOBAL bytecode. So that should be thread-safe, in the sense that bar always points to an object. Its value is never undetermined.

    Of note; it doesn't matter that a float object is immutable. The reference to that object (bar in the example) is mutable. It is that reference that you want to keep defined and unambiguous.

    Second, instead of a getter/setter method in your class Foo I would propose that you use @property decorator. It is considered more Pythonic.

    Edit

    See also the FAQ: What kinds of global value mutation are thread-safe?

    Edit2

    Of course: when in doubt, use e.g. a Lock.