Home  >  Article  >  Backend Development  >  Solutions to problems encountered when php implements multi-process simulation of concurrent transactions

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

不言
不言forward
2018-12-07 17:47:303440browse

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);

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;
    }
}

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
...

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

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

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');
}

to the following:

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

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)

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');

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!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete