当前位置: 首页 > 后端技术 > PHP

php多进程模拟并发事务引起的一些问题

时间:2023-03-29 22:46:46 PHP

tabledroptableifexists`test`;createtableifnotexists`test`(idintnotnullauto_increment,countintdefault0,primarykey`id`(`id`))engine=innodbcharactersetutf8mb4collat??e=utf8mb4_bincomment'testtable';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('从测试中选择`count`');$count=$stmt->fetch(PDO::FETCH_ASSOC)['count'];$计数=整数($计数);如果($count>0){$count--;$pdo->query('更新测试集`count`='.$count.'whereid=2');}$pdo->commit();}catch(Exception$e){$pdo->rollBack();扔$e;}//退出子进程超过100就变成负数了!那是更负!以200并发的实际结果为例,多次运行后的结果如下:1.count=652.count=753.count=554.count=84...与预期结果相差甚远!为什么会出现这样的现象呢?解释一下,首先要明确当前的程序运行环境,并发场景下什么是并发,而且几乎同时执行,这就叫并发。具体解释如下:processprocessgetupdate1-40同时创建并运行1009941-80同时创建并运行999881-100同时创建并运行9897第一行说明上面第一个1-40个子进程的创建几乎是在同一时间,操作几乎是在同一时间:进程1获取count=100,更新99进程2获取计数=100,更新99...进程40getscount=100,updates99那么,其实这些进程都做了同样的操作,不像预期的那样:process1getscount=100,update99;进程2获取进程1count=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的同时,简写为;进程2,简称b,它们的具体执行顺序:1.a查询库存1002.b查询库存1003.a更新库存为99(100-1),这个应该秒懂4.bupdateinventoryto98(99-1)-b在执行update操作的时候得到a更新后的库存!-为什么会这样?因为更新语句是`updatetestsetcount=count-1whereid=2`