php多进程模拟并发事务产生的问题小结
前言
本文通过实例代码给大家介绍了关于php多进程模拟并发事务产生的一些问题,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧
表
droptableifexists`test`; createtableifnotexists`test`( idintnotnullauto_increment, countintdefault0, primarykey`id`(`id`) )engine=innodbcharactersetutf8mb4collate=utf8mb4_bincomment'测试表'; insertintotest(`count`)values(100);
php代码
//进程数量 $pro_count=100; $pids=[]; for($i=0;$i<$pro_count;++$i) { $pid=pcntl_fork(); if($pid<0){ //主进程 thrownewException('创建子进程失败:'.$i); }elseif($pid>0){ //主进程 $pids[]=$pid; }else{ //子进程 try{ $pdo=newPDO(...); $pdo->beginTransaction(); $stmt=$pdo->query('select`count`fromtest'); $count=$stmt->fetch(PDO::FETCH_ASSOC)['count']; $count=intval($count); if($count>0){ $count--; $pdo->query('updatetestset`count`='.$count.'whereid=2'); } $pdo->commit(); }catch(Exception$e){ $pdo->rollBack(); throw$e; } //退出子进程 exit; } }
期望的结果
期望count字段减少的量超过100,变成负数!也就是多减!
实际结果
并发200的情况下,运行多次后的结果分别如下:
1.count=65
2.count=75
3.count=55
4.count=84
...
与期望结果相差甚远!为什么会出现这样的现象呢?
解释
首先清楚下目前的程序运行环境,并发场景。何为并发,几乎同时执行,称之为并发。具体解释如下:
进程过程获取更新
1-40同时创建并运行10099
41-80同时创建并运行9998
81-100同时创建并运行9897
对上述第一行做解释,第1-40个子进程的创建几乎同时,运行也几乎同时:
进程1获取count=100,更新99
进程2获取count=100,更新99
...
进程40获取count=100,更新99
所以,实际上这些进程都做了一致的操作,并没有按照预期的那样:进程1获取count=100,更新99;进程2获取进程1更新后的结果count=99,更新98;...;进程99获取进程98更新后的结果count=1,更新0
,产生的现象就是少减了!!
结论
采用上述做法实现的程序,库存总是>=0。
疑问
那要模拟超库存的场景该如何设计程序呢?
仍然采用上述代码,将以下代码:
if($count>0){ $count--; $pdo->query('updatetestset`count`='.$count.'whereid=2'); }
修改成下面这样:
if($count>0){ $pdo->query('updatetestset`count`=`count`-1whereid=2'); }
结果就会出现超库存!!
库存100,并发200,最终库存减少为-63。为什么会出现这样的情况呢?以下描述了程序运行的具体过程
进程1获取库存100,更新99
进程2获取库存100,更新98(99-1)
进程3获取库存100,更新97(98-1)
....
进程168获取库存1,更新0(1-1)
进程169获取库存1,更新-1(0-1)
进程170获取库存1,更新-2(-1-1)
....
进程200获取库存1,更新-63(-62-1)
现在看来很懵逼,实际就是下面这条语句导致的:
$pdo->query('updatetestset`count`=`count`-1whereid=2');
这边详细阐述进程1,简称a;进程2,简称b他们具体的执行顺序:
1.a查询到库存100
2.b查询到库存100
3.a更新库存为99(100-1),这个应该秒懂
4.b更新库存为98(99-1)
-b在执行更新操作的时候拿到的是a更新后的库存!
-为什么会这样?因为更新语句是`updatetestsetcount=count-1whereid=2`
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。