With example code to introduce some problems about PHP multi-process simulation of concurrent transactions, share out for your reference to learn, the following words do not say much, to look at the detailed introduction

The data 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 the code

The PHP code

$pro_count = 100; $pids = []; for ($i = 0; $i < $pro_count; ++$i) { $pid = pcntl_fork(); If ($pid < 0) {throw new Exception(' create child process failed: '. $I); If ($pid > 0) {$pids[] = $pid; } else {$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 child process exit; }}Copy the code

Desired result

Expect the count field to decrease by more than 100 and become negative! That’s minus a lot!

The actual results

In the case of concurrent 200, the results after multiple runs are as follows:

1. count = 65
 2. count = 75
 3. count = 55
 4. count = 84
Copy the code

Far from the expected results! Why does this happen?

explain

First of all, let’s make clear the current program running environment, concurrent scenario. What is concurrency, executed almost simultaneously, is called concurrency. Specific explanations are as follows:

Process Obtain update 1-40 Simultaneously create and run 100 99 41-80 simultaneously create and run 99 98 81-100 simultaneously create and run 98 97Copy the code

To explain the first line above, child processes 1-40 are created and run at about the same time:

Process 1 get count = 100, update 99... Process 40 gets count = 100 and updates 99Copy the code

So, in fact, these processes are doing something consistent and not as expected: process 1 gets count=100 and updates 99; Count =99, update 98; . ; Count =1, count= 0, count= 0 conclusion

For programs implemented in the above way, inventory is always >= 0.

doubt

So how do you program to simulate an overstock scenario?

Using the above code, add the following code:

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

Change it to the following:

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

The result is overstock!!

Inventory 100, concurrent 200, the final inventory down to -63. Why does this happen? The following describes the specific process of running the program

Process 1 gets inventory 100, updates 99 Process 2 gets inventory 100, updates 98(99-1) Process 3 gets inventory 100, updates 97(98-1).... Process 168 gets inventory 1, update 0 (1-1) Process 169 gets inventory 1, update -1 (0-1) Process 170 gets inventory 1, update -2 (-1-1).... Process 200 fetch inventory 1, update -63 (-62-1)Copy the code

Now it seems confusing, but it’s actually caused by the following statement:

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

Here we elaborate on process 1, a for short; Process 2, referred to as B their specific order of execution:

3. A updated the inventory to 99 (100-1), which should be understood in seconds. 4. B updated the inventory to 98 (99-1) - B got the updated inventory of A when performing the update operation! - Why is that? Update test set count = count - 1 where id = 2Copy the code

I hope the above content can help you. Many PHPer will encounter some problems and bottlenecks when they are advanced, and they have no sense of direction when writing too many business codes. I have sorted out some information, including but not limited to: Distributed architecture, high scalability, high performance, high concurrency, server performance tuning, TP6, Laravel, Redis, Swoft, Kafka, Mysql optimization, shell scripting, Docker, microservices, Nginx, etc. Many knowledge points can be free to share with you