Do I need a lock when using python multi-thread?
Question: Think about this code:

    
    
    #!/usr/bin/env python
    
    from threading import Thread
    
    count = 0
    
    def test():
        global count
        for i in range(10):
            count = count + 1
    
    if __name__ == '__main__':
        for i in range(1000):
            Thread(target = test).start()
        print count
    

I use multiple threads, but the result is always correct. Does that mean I
could use python threads without a lock when implementing something like a
visitor counter ?


Answer: You do need one. Although multithreading works differently in Python, due to
the [Global Interpreter
Lock](http://wiki.python.org/moin/GlobalInterpreterLock), operations that are
not atomic in Python-bytecode will still need locking.

In you case, you can inspect the bytecode for your function `test`
(`dis.dis(test)`):

    
    
     3           0 SETUP_LOOP              30 (to 33)
                 3 LOAD_GLOBAL              0 (range)
                 6 LOAD_CONST               1 (1000)
                 9 CALL_FUNCTION            1
                12 GET_ITER
           >>   13 FOR_ITER                16 (to 32)
                16 STORE_FAST               0 (i)
    
     4          19 LOAD_GLOBAL              1 (count)   # start of increment
                22 LOAD_CONST               2 (1)
                25 BINARY_ADD
                26 STORE_GLOBAL             1 (count)   # end of increment
                29 JUMP_ABSOLUTE           13
           >>   32 POP_BLOCK
           >>   33 LOAD_CONST               0 (None)
                36 RETURN_VALUE
    

As you can see, the increment is a 2xload, update, store on bytecode-level, so
this wont work. The increment is actually 4 separate operations, which you
must protect to ensure they are not interrupted.

In your example the problem remains even if you use `count += 1`, as the
bytecode shows:

    
    
    4          19 LOAD_GLOBAL              1 (count)
               22 LOAD_CONST               2 (1)
               25 INPLACE_ADD
               26 STORE_GLOBAL             1 (count)
    

