概述
多进程并发修改同公共变量时,可能会出现bug,看下面的案例:
案例1
淘宝双十一秒杀时,某商品的数量假设是100件,但有101人在秒杀,100件商品就是全局变量,101人就是101个进程,在秒杀时要做判断,如果商品数量大于0就可以秒杀,否则提示售罄,编码如下:
#coding=utf-8
from multiprocessing import Process,Value
import time
import os
#双十一秒杀
def buy(n,index):
print('%d号买家-开始购买,pid=%d,num=%d'%(index,os.getpid(),n.value))
#修改变量
if n.value>0:
#为了便于查看结果,延迟10秒,开始购买和结束购买会分开
time.sleep(10)
n.value-=1
else:
print('售罄')
print('%d号买家-结束购买,pid=%d,num=%d'%(index,os.getpid(),n.value))
if __name__ == "__main__":
stime=time.time()
#秒杀商品数量
num=Value('i',100)
ps=[]
for index in range(101):
p=Process(target=buy,args=(num,index))
ps.append(p)
for index in range(101):
ps[index].start()
for index in range(101):
ps[index].join()
#主进程打印值
print('主进程,num=%s'%num.value)
etime=time.time()
print(etime-stime)
执行结果的部分截图如下:
下图中,在启动进程时,读取的公共变量初始值都是 100,看到此结果,内心就应该颤抖
注意:多进程是由操作系统调度完成,所以每次运行结果不一样
下图中,34号买家、35号买家购买后的数量都是68,出bug了
问题原因
执行顺序如下:
- 第一步,进程1获取num的值100
- 第二步,进程2获取num的值100
- 第三步,进程1计算后将99写入num
- 第四步,进程2计算后将99写入num
多进程并发访问公共变量时,可能每个进程得到的变量值都是100,计算后赋值时,就都是99
案例2-卖车票
假设有车票500张,有3个售票窗口同时卖票,多进程编程模拟该例子,
注意: 本例sell()函数中有 循环
代码如下:
#coding=utf-8
from multiprocessing import Process,Value
import time
import os
#票总数
count=500
#窗口数量
windownum=3
def sell(n,index):
print('%d号售票口-开始售票,票号:%d,pid=%d'%(index,n.value,os.getpid()))
#修改变量
while n.value<=count:
print('%d号售票口-售出票号:%d,pid=%d'%(index,n.value,os.getpid()))
i=n.value+1
# time.sleep(0.00001)
n.value=i
print('%d号售票口-下一票号:%d,pid=%d'%(index,n.value,os.getpid()))
else:
print('%d号售票口-售罄'%(index))
if __name__ == "__main__":
stime=time.time()
#初始化票号码
num=Value('i',1)
ps=[]
for index in range(windownum):
p=Process(target=sell,args=(num,index))
ps.append(p)
for index in range(windownum):
ps[index].start()
for index in range(windownum):
ps[index].join()
#主进程打印值
print('主进程,num=%s'%num.value)
etime=time.time()
print(etime-stime)
执行结果部分截图如下:
注意:多进程是由操作系统调度完成,所以每次运行结果不一样
问题原因
- 第一步,进程0获取num值为480
- 第二步,进程1获取num值为480
- 第三步,进程1计算后将481赋给num
- 第四步,进程2获取num值为481
- 第五步,进程2计算后将482赋给num
- 第六步,进程0计算后将481赋给num
多进程访问公共变量时,可能多个进程得到同一个值,但在赋值时,一定会有前后顺序
结论
多进程修改公共变量时,一个进程的语句只执行一部分,还没执行完,另一个进程参与进来执行,导致公共变量错误



