简体   繁体   中英

Multithreading with global variable problems in python3

codes like

import threading

def job1():
    global A
    for i in range(10):
        A += 1
        print('job1', A)

def job2():
    global A
    for i in range(10):
        A += 10
        print('job2', A)

if __name__ == '__main__':
    A = 0
    t1 = threading.Thread(target=job1)
    t2 = threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print('all done')

and I run it on python 3.7.3

the result I want to get is like

job1job2 111
job1job2 1222
job1job2 2333
job1job2 3444
job1job2 4555
job1job2 5666
...
all done

but what did I get is

job1 1
job1 2
job1 3
job1 4
job1 5
job1 6
job1 7
job1 8
job1 9
job1 10
job2 20
job2 30
job2 40
job2 50
job2 60
job2 70
job2 80
job2 90
job2 100
job2 110
all done

But I just did not use the lock!

I think this is the result of the code below:

import threading

def job1():
    global A, lock
    lock.acquire()
    for i in range(10):
        A += 1
        print('job1', A)
    lock.release()

def job2():
    global A, lock
    lock.acquire()
    for i in range(10):
        A += 10
        print('job2', A)
    lock.release()

if __name__ == '__main__':
    A = 0
    lock = threading.Lock()
    t1 = threading.Thread(target=job1)
    t2 = threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print('all done')

Why am I not getting the output I expect?

Python offers no guarantee about exactly when a thread will run. What is apparently happening is that Python starts executing the job1() thread, and it runs to completion, going through all 10 iterations of its loop, before it starts running the job2() thread.

There's no way to predict how two threads will be scheduled. For that reason, trusting in any kind of sharing of a global resource like you're doing, without using some kind of controls, like locks or semaphores, or thread-safe classes, is asking for trouble most of the time. For that reason, the locking version of your code, while not giving you the output you want, is a better way to think about having these two threads work together.

BTW, you don't need to call global lock inside your functions. That would just allow you to point the global lock reference to a different Lock object, or to otherwise change the contents of that variable. The Lock object's behavior won't be affected by that call.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM