python-多线程修改公共变量引发的血案 作者:马育民 • 2019-02-22 11:07 • 阅读:10619 # 概述 多线程并发修改同公共变量时,可能会出现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)) ``` **执行结果如下:** [![](http://www.malaoshi.top/upload/0/0/1EF2qIaausKl.png)](http://www.malaoshi.top/upload/0/0/1EF2qIaausKl.png) 两个线程分别循环100000次,结果应该是200000,那么执行结果不正确 **说明:** 在本程序中,一个线程中有两个线程,线程在执行时由系统调度,顺序不确定,顺序可能如下: 1. 第一步,线程1获取num的值0 2. 第二步,线程2获取num的值0 3. 第三步,线程1计算后将1写入num 4. 第四步,线程2计算后将1写入num 多线程并发访问公共变量时,可能每个线程得到的变量值是相同的,计算后赋值时,也是相同的 [![](http://www.malaoshi.top/upload/0/0/1EF391g6MLGc.png)](http://www.malaoshi.top/upload/0/0/1EF391g6MLGc.png) # 案例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) ``` ##### 执行结果部分截图如下: 不同窗口卖出同一张票 [![](http://www.malaoshi.top/upload/0/0/1EF391NGia1L.png)](http://www.malaoshi.top/upload/0/0/1EF391NGia1L.png) >注意:多进程是由操作系统调度完成,所以每次运行结果不一样 ### 原因 执行顺序如下: [![](http://www.malaoshi.top/upload/0/0/1EF391ZEMXWU.png)](http://www.malaoshi.top/upload/0/0/1EF391ZEMXWU.png) 第一步,线程1获取num的值495 第二步,线程2获取num的值495 第三步,线程1计算后将496写入num 第四步,线程2计算后将496写入num ### 结论 多线程修改公共变量时,一个线程只执行一部分,还没执行完,另一个线程参与进来执行,导致公共变量错误 原文出处:http://malaoshi.top/show_1EF2qKOtyKA8.html