Solutions to problems encountered when php implements multi-process simulation of concurrent transactions

不言
Release: 2023-04-04 14:16:01
forward
3450 people have browsed it

The content of this article is about solutions to problems encountered when php implements multi-process simulation of concurrent transactions. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

Table

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);
Copy after login

php code

// 进程数量
$pro_count = 100;
$pids = [];
for ($i = 0; $i < $pro_count; ++$i)
{
    $pid = pcntl_fork();
    if ($pid < 0) {
        // 主进程
        throw new Exception(&#39;创建子进程失败: &#39; . $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;
    }
}
Copy after login

desired result

Expect the count field to decrease by more than 100 and become a negative number! That is to say, reduce more!

Actual results

In the case of 200 concurrency, the results after running multiple times are as follows:

1. count = 65
2. count = 75
3. count = 55
4. count = 84
...
Copy after login

It is far from the expected results! Why does this happen?

Explanation

First, clearly understand the current program running environment and concurrency scenarios. What is concurrency? Execution almost simultaneously is called concurrency. The specific explanation is as follows:

进程        过程            获取    更新
1-40        同时创建并运行  100     99
41-80       同时创建并运行  99      98
81 - 100    同时创建并运行  98      97
Copy after login

Explain the first line above, the sub-processes 1-40 are created almost at the same time and run almost at the same time:

进程 1 获取 count = 100,更新 99
进程 2 获取 count = 100,更新 99
...
进程 40 获取 count = 100,更新 99
Copy after login

So, In fact, these processes all performed the same operation, but not as expected: process 1 obtained count=100, updated 99; process 2 obtained the updated result of process 1, count=99, updated 98; ...; process 99 Get the updated result of process 98, count=1, update 0
, the resulting phenomenon is that it decreases! !

Conclusion

The program implemented using the above approach, the inventory is always >= 0.

Question

How to design a program to simulate an over-stocking scenario?

Still using the above code, modify the following code:

if ($count > 0) {
    $count--;
    $pdo->query('update test set `count` = ' . $count . ' where id = 2');
}
Copy after login

to the following:

if ($count > 0) {
    $pdo->query('update test set `count` = `count` - 1 where id = 2');
}
Copy after login

The result will be overstock! !

Inventory 100, concurrency 200, final inventory reduced to -63. Why is there such a situation? The following describes the specific process of program operation

进程 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)
Copy after login

It seems very confusing now, but it is actually caused by the following statement:

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

Here is a detailed explanationProcess 1, referred to as a ; Process 2, referred to as b Their specific execution sequence:

1. a Query the inventory 100
2. b Query the inventory 100
3. a Update the inventory to 99 (100 - 1), this should be understood in seconds
4. b updates the inventory to 98 (99 - 1)
- b When performing the update operation, what is obtained is the updated inventory of a!
- Why is this happening? Because the update statement is `update test set count = count - 1 where id = 2`

The above is the detailed content of Solutions to problems encountered when php implements multi-process simulation of concurrent transactions. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:segmentfault.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template