• 售前

  • 售后

热门帖子
入门百科

php多进程模拟并发事件产生的问题小结

[复制链接]
刘和谐1 显示全部楼层 发表于 2021-10-26 12:43:36 |阅读模式 打印 上一主题 下一主题
前言
本文通过实例代码给各人先容了关于php多历程模仿并发事务产生的一些题目,分享出来供各人参考学习,下面话不多说了,来一起看看具体的先容吧

  1. drop table if exists `test`;
  2. create table if not exists `test` (
  3. id int not null auto_increment ,
  4. count int default 0 ,
  5. primary key `id` (`id`)
  6. ) engine=innodb character set utf8mb4 collate = utf8mb4_bin comment '测试表';
  7. insert into test (`count`) values (100);
复制代码
php 代码
  1. // 进程数量
  2. $pro_count = 100;
  3. $pids = [];
  4. for ($i = 0; $i < $pro_count; ++$i)
  5. {
  6. $pid = pcntl_fork();
  7. if ($pid < 0) {
  8.   // 主进程
  9.   throw new Exception('创建子进程失败: ' . $i);
  10. } else if ($pid > 0) {
  11.   // 主进程
  12.   $pids[] = $pid;
  13. } else {
  14.   // 子进程
  15.   try {
  16.    $pdo = new PDO(...);
  17.    $pdo->beginTransaction();
  18.    $stmt = $pdo->query('select `count` from test');
  19.    $count = $stmt->fetch(PDO::FETCH_ASSOC)['count'];
  20.    $count = intval($count);
  21.    if ($count > 0) {
  22.     $count--;
  23.     $pdo->query('update test set `count` = ' . $count . ' where id = 2');
  24.    }
  25.    $pdo->commit();
  26.   } catch(Exception $e) {
  27.    $pdo->rollBack();
  28.    throw $e;
  29.   }
  30.   // 退出子进程
  31.   exit;
  32. }
  33. }
复制代码
盼望的效果

盼望 count 字段减少的量凌驾 100,变成负数!也就是多减!
实际效果

并发 200 的情况下,运行多次后的效果分别如下:
  1. 1. count = 65
  2. 2. count = 75
  3. 3. count = 55
  4. 4. count = 84
  5. ...
复制代码
与盼望效果相差甚远!为什么会出现这样的征象呢?
表明

起首清楚下现在的步伐运行情况,并发场景。作甚并发,险些同时实行,称之为并发。具体表明如下:
  1. 进程 过程 获取 更新
  2. 1-40 同时创建并运行 100 99
  3. 41-80 同时创建并运行 99 98
  4. 81 - 100 同时创建并运行 98 97
复制代码
对上述第一行做表明,第 1-40 个子历程的创建险些同时,运行也险些同时:
  1. 进程 1 获取 count = 100,更新 99
  2. 进程 2 获取 count = 100,更新 99
  3. ...
  4. 进程 40 获取 count = 100,更新 99
复制代码
以是,实际上这些历程都做了同等的操作,并没有按照预期的那样:历程1 获取 count=100,更新 99;历程 2 获取历程1更新后的效果 count=99,更新98;...;历程 99 获取历程 98更新后的效果count=1,更新0
,产生的征象就是少减了!!
结论

接纳上述做法实现的步伐,库存总是 >= 0。
疑问

那要模仿超库存的场景该如何设计步伐呢?
仍然接纳上述代码,将以下代码:
  1. if ($count > 0) {
  2. $count--;
  3. $pdo->query('update test set `count` = ' . $count . ' where id = 2');
  4. }
复制代码
修改成下面这样:
  1. if ($count > 0) {
  2. $pdo->query('update test set `count` = `count` - 1 where id = 2');
  3. }
复制代码
效果就会出现超库存!!
库存 100,并发 200,最终库存减少为 -63。为什么会出现这样的情况呢?以下描述了步伐运行的具体过程
  1. 进程 1 获取库存 100,更新 99
  2. 进程 2 获取库存 100,更新 98(99 - 1)
  3. 进程 3 获取库存 100,更新 97(98 - 1)
  4. ....
  5. 进程 168 获取库存 1 ,更新 0(1-1)
  6. 进程 169 获取库存 1 ,更新 -1(0 - 1)
  7. 进程 170 获取库存 1 ,更新 -2(-1 - 1)
  8. ....
  9. 进程 200 获取库存 1,更新 -63(-62 - 1)
复制代码
现在看来很懵逼,实际就是下面这条语句导致的:
  1. $pdo->query('update test set `count` = `count` - 1 where id = 2');
复制代码
这边具体论述 历程 1,简称 a;历程 2,简称 b 他们具体的实行次序:
  1. 1. a 查询到库存 100
  2. 2. b 查询到库存 100
  3. 3. a 更新库存为 99(100 - 1),这个应该秒懂
  4. 4. b 更新库存为 98(99 - 1)
  5. - b 在执行更新操作的时候拿到的是 a 更新后的库存!
  6. - 为什么会这样?因为更新语句是 `update test set count = count - 1 where id = 2`
复制代码
总结
以上就是这篇文章的全部内容了,希望本文的内容对各人的学习大概工作具有一定的参考学习代价,如果有疑问各人可以留言交换,谢谢各人对草根技术分享的支持。

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作