前言
表drop table if exists `test程式設計客棧www.cppcns.com`;
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)
else if ($pid > 0) else
$pdo->commit();
} catch(exception $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 > 0)
修改成下面這樣:
if ($count > 0)
結果就會出現超庫存程式設計客棧!!
庫存 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 在執行更新操作的時候拿到的是 a 更新後的庫存!
- 為什麼會這樣?因為更新語句是 `update test set count = count - 1 where id = 2`
總結本文標題: php多程序模擬併發事務產生的問題小結
本文位址:
PHP的多程序
一般有兩種方法,一種是使用php自帶的pcntl 函式 僅限linux 另一種就是使用popen proc open,然後在php內部控制程序數量。php提供了一系列的pcntl 函式,顧名思義就是process control functions,專門用來管理程序的。最常用的就是pcntl for...
PHP的多程序
一般有兩種方法,一種是使用php自帶的pcntl 函式 僅限linux 另一種就是使用popen proc open,然後在php內部控制程序數量。php提供了一系列的pcntl 函式,顧名思義就是process control functions,專門用來管理程序的。最常用的就是pcntl for...
PHP多程序併發控制的測試用例
轉http blog.s135.com post 311 最近遇到乙個問題,linux下的php命令列程式作為守護程序,需要從佇列檔案中讀一行資料,通過tcp協議傳送給外地的接收伺服器,再讀下一行資料,再傳送。當本地與外地的網路狀況不好時,有時候傳送一條資料所耗費的時間就較長,累積起來容易造成佇列堵...