在多线程中,同一个变量能被所有线程共享,这个变量能被任何一个线程修改。
看一个实验。
启动5个线程,每个线程把全局变量加1
import threading import time t_objs = [] def run(n): global num num+=1 num = 0 for i in range(5): t = threading.Thread(target=run,args=("t-%s" %i,)) t.start() t_objs.append(t) for t in t_objs: t.join() print('num:',num) #num: 5
启动了5个线程,每个线程加1,一共是5个,所以结果是5没有问题。
python2.7下执行:
50个线程,num相加50次,也没有问题。1000个线程相加也是没有问题的。
尝试相减,启动1000个线程,每个线程减1。
子线程不等待,主线程等待3s。
根据GIL同一时间只有一个线程在执行,但是并不能保证数据是正确的。这个现象在其它系统中会出现。
线程1拿到的count = 0; 但是线程1没有执行完就被挂起了。紧接着执行线程2,线程2执行完成,并且把count=1赋值给count。这个时候线程1又继续执行,但是之前的线程因为被挂起,所以数据保存在了寄存器里面,并没有在次取数据,这个时候count还是0。那么线程1执行完count++之后count=1,又赋值给了count。最后count的数值还是1,这个计算并不准确。
这个怎么保证数据的准确性呢?
理想的状态下,我们希望启动线程时并行,计算数值时串行。
这个时候需要用户自己加一个锁,这个锁和GIL无关。这个锁是保证同一时间只有一个线程在修改数据。
import threading import time t_objs = [] def run(n): lock.acquire() #添加锁 global num num+=1 lock.release()#释放锁 num = 0 lock = threading.Lock() #锁的实例 for i in range(500): t = threading.Thread(target=run,args=("t-%s" %i,)) t.start() t_objs.append(t) for t in t_objs: t.join() print('num:',num) #num: 500
可以 验证计算是否是串行,在计算的时候sleep.
import threading import time t_objs = [] def run(n): lock.acquire() #添加锁 global num num+=1 time.sleep(1) lock.release()#释放锁 num = 0 lock = threading.Lock() #锁的实例 for i in range(5): t = threading.Thread(target=run,args=("t-%s" %i,)) t.start() t_objs.append(t) for t in t_objs: t.join() print('num:',num) #等待5s num: 5
以上现象在2.X会出现。