温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

PHP 中并发的场景有哪些

发布时间:2021-06-03 18:06:36 来源:亿速云 阅读:195 作者:Leah 栏目:开发技术

PHP 中并发的场景有哪些?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

一、利用 Redis 事务特征

redis 事务是原子操作,可以保证订单处理的过程中数据没有被其它并发的进程修改。

示例代码:

<?php $http = new swoole_http_server("0.0.0.0", 9509);  // 监听 9509 $http->set(array(   'reactor_num' => 2, //reactor thread num   'worker_num' => 4  //worker process num )); $http->on('request', function (swoole_http_request $request, swoole_http_response $response) {   $uniqid = uniqid('uid-', TRUE);  // 模拟唯一用户ID   $redis = new Redis();   $redis->connect('127.0.0.1', 6379);  // 连接 redis   $redis->watch('rest_count'); // 监测 rest_count 是否被其它的进程更改   $rest_count = intval($redis->get("rest_count")); // 模拟唯一订单ID   if($rest_count > 0){     $value = "{$rest_count}-{$uniqid}"; // 表示当前订单,被当前用户抢到了     // do something ... 主要是模拟用户抢到单后可能要进行的一些密集运算     $rand = rand(100, 1000000);     $sum=0;     for ($i=0;$i<$rand;$i++){ $sum+=$i; }    // redis 事务     $redis->multi();     $redis->lPush('uniqids', $value);     $redis->decr('rest_count');     $replies = $redis->exec(); // 执行以上 redis 事务    // 如果 rest_count 的值被其它的并发进程更改了,以上事务将回滚     if(!$replies){       echo "订单 {$value} 回滚".PHP_EOL;     }   }   $redis->unwatch(); }); $http->start();

使用 ab 测试

$ ab -t 20 -c 10 http://192.168.1.104:9509/

二、利用文件排他锁(阻塞模式)

阻塞模式下,如果进程在获取文件排他锁时,其它进程正在占用锁的话,此进程会挂起等待其它进程释放锁后,并自己获取到锁后,再往下执行。

示例代码:

<?php $http = new swoole_http_server("0.0.0.0", 9510); $http->set(array(   'reactor_num' => 2, //reactor thread num   'worker_num' => 4  //worker process num )); $http->on('request', function (swoole_http_request $request, swoole_http_response $response) {   $uniqid = uniqid('uid-', TRUE);   $redis = new Redis();   $redis->connect('127.0.0.1', 6379);   $fp = fopen("lock.txt", "w+");   // 阻塞(等待)模式, 要取得独占锁定(写入的程序)   if(flock($fp,LOCK_EX))  //锁定当前指针   {    // 成功取得锁后,放心处理订单     $rest_count = intval($redis->get("rest_count"));     $value = "{$rest_count}-{$uniqid}";     if($rest_count > 0){       // do something ...       $rand = rand(100, 1000000);       $sum=0;       for ($i=0;$i<$rand;$i++){ $sum+=$i; }       $redis->lPush('uniqids', $value);       $redis->decr('rest_count');     }    // 订单处理完成后,再释放锁     flock($fp,LOCK_UN);   }   fclose($fp); }); $http->start();

使用 ab 测试

$ ab -t 20 -c 10 http://192.168.1.104:9510/

三、利用文件排他锁(非阻塞模式)

非阻塞模式下,如果进程在获取文件排他锁时,其它进程正在占用锁的话,此进程会马上判断获取锁失败,并且继续往下执行。

示例代码:

<?php $http = new swoole_http_server("0.0.0.0", 9511); $http->set(array(   'reactor_num' => 2, //reactor thread num   'worker_num' => 4  //worker process num )); $http->on('request', function (swoole_http_request $request, swoole_http_response $response) {   $uniqid = uniqid('uid-', TRUE);   $redis = new Redis();   $redis->connect('127.0.0.1', 6379);   $fp = fopen("lock.txt", "w+");   // 非阻塞模式, 如果不希望 flock() 在锁定时堵塞,则给 lock 加上 LOCK_NB   if(flock($fp,LOCK_EX | LOCK_NB))  //锁定当前指针   {    // 成功取得锁后,放心处理订单     $rest_count = intval($redis->get("rest_count"));     $value = "{$rest_count}-{$uniqid}";     if($rest_count > 0){       // do something ...       $rand = rand(100, 1000000);       $sum=0;       for ($i=0;$i<$rand;$i++){ $sum+=$i; }       $redis->lPush('uniqids', $value);       $redis->decr('rest_count');     }    // 订单处理完成后,再释放锁     flock($fp,LOCK_UN);   } else {    // 如果获取锁失败,马上进入这里执行     echo "{$uniqid} - 系统繁忙,请稍后再试".PHP_EOL;   }   fclose($fp); }); $http->start();

使用 ab 测试

$ ab -t 20 -c 10 http://192.168.1.104:9511/

最后给出三种处理方式的测试结果比较

redis 事务方式:

...... Concurrency Level:   10 Time taken for tests:  20.005 seconds Complete requests:   17537 Failed requests:    0 Total transferred:   2578380 bytes HTML transferred:    0 bytes Requests per second:  876.62 [#/sec] (mean) Time per request:    11.407 [ms] (mean) Time per request:    1.141 [ms] (mean, across all concurrent requests) Transfer rate:     125.86 [Kbytes/sec] received ......

文件排他锁(阻塞模式):

...... Concurrency Level:   10 Time taken for tests:  20.003 seconds Complete requests:   8205 Failed requests:    0 Total transferred:   1206282 bytes HTML transferred:    0 bytes Requests per second:  410.19 [#/sec] (mean) Time per request:    24.379 [ms] (mean) Time per request:    2.438 [ms] (mean, across all concurrent requests) Transfer rate:     58.89 [Kbytes/sec] received ......

文件排他锁(非阻塞模式):

...... Concurrency Level:   10 Time taken for tests:  20.002 seconds Complete requests:   8616 Failed requests:    0 Total transferred:   1266846 bytes HTML transferred:    0 bytes Requests per second:  430.77 [#/sec] (mean) Time per request:    23.214 [ms] (mean) Time per request:    2.321 [ms] (mean, across all concurrent requests) Transfer rate:     61.85 [Kbytes/sec] received ......

关于PHP 中并发的场景有哪些问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

php
AI