Maison  >  Article  >  développement back-end  >  Solutions aux problèmes rencontrés lorsque PHP implémente la simulation multi-processus de transactions simultanées

Solutions aux problèmes rencontrés lorsque PHP implémente la simulation multi-processus de transactions simultanées

不言
不言avant
2018-12-07 17:47:303386parcourir

Le contenu de cet article concerne les solutions aux problèmes rencontrés lorsque php implémente la simulation multi-processus de transactions simultanées. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Tableau

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

code php

// 进程数量
$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;
    }
}

Résultat souhaité

Le champ de comptage devrait diminuer de plus de 100 et devenir un nombre négatif ! C’est-à-dire réduire davantage !

Résultats réels

Dans le cas de 200 simultanéités, les résultats après exécution plusieurs fois sont les suivants :

1. count = 65
2. count = 75
3. count = 55
4. count = 84
...

C'est loin d'être le résultat attendu ! Pourquoi cela arrive-t-il ?

Explication

Tout d'abord, comprenons clairement l'environnement d'exécution actuel du programme et les scénarios de concurrence. Qu'est-ce que la concurrence ? L'exécution presque simultanée est appelée concurrence. L'explication spécifique est la suivante :

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

Pour expliquer la première ligne ci-dessus, le sous-processus 1-40 est créé presque en même temps et s'exécute presque en même temps :

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

Donc, en fait, ces processus ont tous effectué des opérations cohérentes et n'ont pas fonctionné comme prévu : le processus 1 a obtenu le nombre = 100 et a mis à jour 99 ; le processus 2 a obtenu le résultat mis à jour du processus 1, nombre = 99 et a mis à jour 98 ; .; processus 99 processus obtenu Le résultat mis à jour de 98 est count=1, mise à jour 0
, et le phénomène qui en résulte est qu'il diminue ! !

Conclusion

Dans le programme mis en œuvre selon l'approche ci-dessus, l'inventaire est toujours >= 0.

Question

Comment concevoir un programme pour simuler un scénario de surstockage ?

Toujours en utilisant le code ci-dessus, changez le code suivant :

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

par le suivant :

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

Le résultat sera en surstock ! !

Inventaire 100, simultanéité 200, inventaire final réduit à -63. Pourquoi cela arrive-t-il ? Ce qui suit décrit le processus spécifique d'exécution du programme

进程 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)

Cela semble très déroutant maintenant, mais cela est en fait causé par la déclaration suivante :

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

Élaborez ici进程 1,简称 a;进程 2,简称 bIls Séquence d'exécution spécifique :

1. a Interroger l'inventaire 100
2. b Interroger l'inventaire 100
3 a Mettre à jour l'inventaire à 99 (100 - 1), cela doit être compris en quelques secondes.
4. b met à jour l'inventaire à 98 (99 - 1)
- b obtient l'inventaire mis à jour de a lors de l'exécution de l'opération de mise à jour !
- Pourquoi cela arrive-t-il ? Parce que l'instruction de mise à jour est `update test set count = count - 1 où id = 2`

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer