php多进程模拟并发事务产生的问题,可学习参考

用实例代码给大家介绍关于php多进程模拟并发事务产生的一些问题,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧

数据表

droptableifexists`test`;

createtableifnotexists`test`(

idintnotnullauto_increment ,

countintdefault,

primarykey`id`(`id`)

)engine=innodbcharactersetutf8mb4collate= utf8mb4_bincomment'测试表';

insertintotest(`count`)values(100);

php 代码

// 进程数量

$pro_count =100;

$pids = [];

for($i =; $i

{

$pid = pcntl_fork();

if($pid

// 主进程

thrownewException('创建子进程失败: '. $i);

}elseif($pid >) {

// 主进程

$pids[] = $pid;

}else{

// 子进程

try{

$pdo =newPDO(...);

$pdo->beginTransaction();

$stmt = $pdo->query('select `count` from test');

$count = $stmt->fetch(PDO::FETCH_ASSOC)['count'];

$count = intval($count);

if($count >) {

$count--;

$pdo->query('update test set `count` = '. $count .' where id = 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 同时创建并运行 100 99

41-80 同时创建并运行 99 98

81 - 100 同时创建并运行 98 97

对上述第一行做解释,第 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 >) {

$count--;

$pdo->query('update test set `count` = '. $count .' where id = 2');

}

修改成下面这样:

if($count >) {

$pdo->query('update test set `count` = `count` - 1 where id = 2');

}

结果就会出现超库存!!

库存 100,并发 200,最终库存减少为 -63。为什么会出现这样的情况呢?以下描述了程序运行的具体过程

现在看来很懵逼,实际就是下面这条语句导致的:

$pdo->query('update test set `count` = `count` - 1 where id = 2');

这边详细阐述 进程 1,简称 a;进程 2,简称 b 他们具体的执行顺序:

1.a 查询到库存 100

2.b 查询到库存 100

3.a 更新库存为 99(100 - 1),这个应该秒懂

4.b 更新库存为 98(99 - 1)

-b 在执行更新操作的时候拿到的是 a 更新后的库存!

-为什么会这样?因为更新语句是`update test set count = count - 1 where id = 2`

以上内容希望帮助到大家,有需要可以添加下方二维码进群交流学习新技术。

如果你想和PHP大神交流加微信,拉你入群

如果你想获得学习资料加微信,送你资源

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190125A0HI5V00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券