Quantcast
Channel: User selbie - Stack Overflow
Viewing all articles
Browse latest Browse all 102

Answer by selbie for Did the threading module change in Python 3? And if so, how?

$
0
0

Regardless if the threading behavior changed between version of python, without using a lock, the behavior of incrementing num across multiple unsynchronized threads is going to be non-deterministic at best. Even with multiple runs on the same interpreter on the same PC, it could generate different results. Because you never know when a context switch on a thread could occur.

This statement:

num += 1

Is just shorthand for something nearly equivalent to this at run time.

REGISTER = num            # read memory location into a local registerREGISTER = REGISTER + 1   # increment the valuenum = REGISTER            # store back to memory

And since any thread could get preempted by another thread or get scheduled on a different core, or the print call itself could introduce weird timing issues. There's all the cache coherency issue of multiple cores. It's entirely possible something like this is happening at run time.

 THREAD 1:       REGISTER  = num          # T1 reads 0 into register<context switch> THREAD 2:      REGISTER = num            #T2 reads "0" into register     REGISTER = REGISTER + 1   #T2 increments register to "1"     num = REGISTER            #T2 copies register value back to memory<context switch back to thread 1, REGISTER is restored to "0" from before><but the memory location for num is now 1> THREAD 1:      REGISTER = REGISTER + 1   #T1 increments register to "1"     num = REGISTER            #T1 copy register value ("1") back to memory

So as above, it's very easy for two threads to have overlapping access to a variable.

You need a lock if you want consistent behavior of num getting incremented to 5. An easy update:

 lock = Lock() class meThread(threading.Thread):    def run(self):       global num       global lock       time.sleep(random.randint(1,3))       # --------------------------------       lock.acquire()       num += 1       tmp = num          # save value a local tmp value for the subsequent print       lock.release()       # --------------------------------       print(self.name+'set num to '+str(tmp))  # print the value of what num was incremented to while in the lock, not what num is now

Everything you need to know is here.


Viewing all articles
Browse latest Browse all 102

Latest Images

Trending Articles





Latest Images