この記事の内容は、php で同時トランザクションのマルチプロセスシミュレーションを実装する際に発生する問題の解決策について書いたもので、一定の参考値がありますので、困っている方は参考にしていただければ幸いです。
テーブル
drop table if exists `test`; create table if not exists `test` ( id int not null auto_increment , count int default 0 , primary key `id` (`id`) ) engine=innodb character set utf8mb4 collate = utf8mb4_bin comment '测试表'; insert into test (`count`) values (100);
phpコード
// 进程数量 $pro_count = 100; $pids = []; for ($i = 0; $i < $pro_count; ++$i) { $pid = pcntl_fork(); if ($pid < 0) { // 主进程 throw new Exception('创建子进程失败: ' . $i); } else if ($pid > 0) { // 主进程 $pids[] = $pid; } else { // 子进程 try { $pdo = new PDO(...); $pdo->beginTransaction(); $stmt = $pdo->query('select `count` from test'); $count = $stmt->fetch(PDO::FETCH_ASSOC)['count']; $count = intval($count); if ($count > 0) { $count--; $pdo->query('update test set `count` = ' . $count . ' where id = 2'); } $pdo->commit(); } catch(Exception $e) { $pdo->rollBack(); throw $e; } // 退出子进程 exit; } }
望ましい結果
カウント フィールドが 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 はカウント = 100 を取得、更新 99; プロセス 2 はプロセス 1 の更新結果を取得、カウント = 99、更新 98; ...; 処理99 処理98の更新結果を取得、count=1、更新0
、結果として減少するという現象が発生! !
結論
上記のアプローチを使用して実装されたプログラムでは、在庫は常に 0 以上になります。
質問
在庫過剰シナリオをシミュレートするプログラムを設計するにはどうすればよいですか?
引き続き上記のコードを使用し、次のコードを変更します:
if ($count > 0) { $count--; $pdo->query('update test set `count` = ' . $count . ' where id = 2'); }
を次のように変更します:
if ($count > 0) { $pdo->query('update test set `count` = `count` - 1 where id = 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('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 更新操作を実行すると、取得されるのは更新されたインベントリですああ! ### - なぜこうなった? update ステートメントは「update test set count = count - 1 where id = 2」であるため、
以上がPHP が同時トランザクションのマルチプロセス シミュレーションを実装するときに発生する問題の解決策の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。