WoooHaaaa
WoooHaaaa

Reputation: 20470

Do I need a lock when using python multi-thread?

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 ?

Upvotes: 4

Views: 864

Answers (3)

Björn Pollex
Björn Pollex

Reputation: 76886

You do need one. Although multithreading works differently in Python, due to the Global Interpreter Lock, 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)

Upvotes: 6

glglgl
glglgl

Reputation: 91149

You wouldn't need a lock if you just did assignments.

But as you do count = count + 1, something can happen between each of reading out count, adding 1 and writing to count.

Even using count += 1 wouldn't solve this problem, as this involves an assignment as well. (As the inplace operations involve an assignment under the hood as well, the situation is the same.)

Upvotes: 1

crow16384
crow16384

Reputation: 597

Definitely you should use Lock. You have got a correct answer in such simple case. Try to make it for range(100000) in main. You will see the problem. In my machine the result is 999960, but it is random result. Errors will arise depending on system load and so on.

Upvotes: 0

Related Questions