python-多线程修改公共变量引发的血案

概述

多线程并发修改同公共变量时,可能会出现bug

案例1

#coding=utf-8
import threading

num=0

def modify():
    global num
    #获取当前线程对象
    t=threading.current_thread()
    #注意:至少要循环10万次
    for index in range(100000):
        num+=1


if __name__ == "__main__":
    #创建线程,此线程修改全局变量
    t=threading.Thread(target=modify)
    #创建线程,此线程打印全局变量
    t2=threading.Thread(target=modify)
    #启动线程
    t.start()
    t2.start()
    #阻塞
    t.join()
    t2.join()
    print('执行结束,num=%d'%(num))

执行结果如下:

两个线程分别循环100000次,结果应该是200000,那么执行结果不正确

说明:
在本程序中,一个线程中有两个线程,线程在执行时由系统调度,顺序不确定,顺序可能如下:

  1. 第一步,线程1获取num的值0
  2. 第二步,线程2获取num的值0
  3. 第三步,线程1计算后将1写入num
  4. 第四步,线程2计算后将1写入num

多线程并发访问公共变量时,可能每个线程得到的变量值是相同的,计算后赋值时,也是相同的

案例2

假设有车票500张,有3个售票窗口同时卖票,多线程编程模拟该例子,

注意: 本例sell()函数中有 循环

代码如下:

#coding=utf-8
from threading import Thread
import time

#票总数
count=500
#窗口数量
windownum=3
#初始化票号码
num=1

def sell(index):
    global num
    print('%d号售票口-开始售票,票号:%d'%(index,num))
    #修改变量
    while num<=count:
        print('%d号售票口-售出票号:%d'%(index,num))
        i=num+1
        # time.sleep(0.00001)
        num=i
        print('%d号售票口-下一票号:%d'%(index,num))
    else:
        print('%d号售票口-售罄'%(index))

if __name__ == "__main__":
    stime=time.time()
    ts=[]
    for index in range(windownum):
        t=Thread(target=sell,args=(index,))
        ts.append(t)
    for item in ts:
        item.start()
    for item in ts:
        item.join()

    #主进程打印值
    print('主进程,num=%s'%num)
    etime=time.time()
    print(etime-stime)
执行结果部分截图如下:

不同窗口卖出同一张票

注意:多进程是由操作系统调度完成,所以每次运行结果不一样

原因

执行顺序如下:

第一步,线程1获取num的值495
第二步,线程2获取num的值495
第三步,线程1计算后将496写入num
第四步,线程2计算后将496写入num

结论

多线程修改公共变量时,一个线程只执行一部分,还没执行完,另一个线程参与进来执行,导致公共变量错误


原文出处:/show_1EF2qKOtyKA8.html