五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

知識(shí)分享!PHP并發(fā)場景的三種解決方案

2021-01-06 14:08 作者:光耀三十洲  | 我要投稿

在秒殺,搶購等并發(fā)場景下,可能會(huì)出現(xiàn)超賣的現(xiàn)象,在 PHP 語言中并沒有原生提供并發(fā)的解決方案,因此就需要借助其他方式來實(shí)現(xiàn)并發(fā)控制,其實(shí)方案有很多種,今天只是舉個(gè)栗子拋磚引玉,有其他更好的方案你可以自己去玩一玩就好了。

列出常見的3個(gè)解決方案有:

使用隊(duì)列,額外起一個(gè)進(jìn)程處理隊(duì)列,并發(fā)請(qǐng)求都放到隊(duì)列中,由額外進(jìn)程串行處理,并發(fā)問題就不存在了,但是要額外進(jìn)程支持以及處理延遲嚴(yán)重,本文不先不討論這種方法。

利用數(shù)據(jù)庫事務(wù)特征,做原子更新,此方法需要依賴數(shù)據(jù)庫的事務(wù)特性。

借助文件排他鎖,在處理下單請(qǐng)求的時(shí)候,用 flock 鎖定一個(gè)文件,成功拿到鎖的才能處理訂單。

一、利用 Redis 事務(wù)特征

redis 事務(wù)是原子操作,可以保證訂單處理的過程中數(shù)據(jù)沒有被其它并發(fā)的進(jìn)程修改。

示例代碼:

<?php

$http = new swoole_http_server("0.0.0.0", 9509);? ?// 監(jiān)聽 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');? // 監(jiān)測(cè) rest_count 是否被其它的進(jìn)程更改

?$rest_count = intval($redis->get("rest_count"));? // 模擬唯一訂單ID

?if ($rest_count > 0){

?$value = "{$rest_count}-{$uniqid}";? // 表示當(dāng)前訂單,被當(dāng)前用戶搶到了

?// do something ... 主要是模擬用戶搶到單后可能要進(jìn)行的一些密集運(yùn)算

?$rand = rand(100, 1000000);

?$sum = 0;

?for ($i = 0; $i < $rand; $i++) {$sum += $i;}

?// redis 事務(wù)

?$redis->multi();

?$redis->lPush('uniqids', $value);

?$redis->decr('rest_count');

?$replies = $redis->exec();? // 執(zhí)行以上 redis 事務(wù)

?// 如果 rest_count 的值被其它的并發(fā)進(jìn)程更改了,以上事務(wù)將回滾

?if (!$replies) {

?echo "訂單 {$value} 回滾" . PHP_EOL;

?}

?}

?$redis->unwatch();

});

$http->start();


使用 ab 測(cè)試

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


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

阻塞模式下,如果進(jìn)程在獲取文件排他鎖時(shí),其它進(jìn)程正在占用鎖的話,此進(jìn)程會(huì)掛起等待其它進(jìn)程釋放鎖后,并自己獲取到鎖后,再往下執(zhí)行。

示例代碼:

<?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+");

?// 阻塞(等待)模式, 要取得獨(dú)占鎖定(寫入的程序)

?if (flock($fp,LOCK_EX)) {? //鎖定當(dāng)前指針

?// 成功取得鎖后,放心處理訂單

?$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 測(cè)試

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


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

非阻塞模式下,如果進(jìn)程在獲取文件排他鎖時(shí),其它進(jìn)程正在占用鎖的話,此進(jìn)程會(huì)馬上判斷獲取鎖失敗,并且繼續(xù)往下執(zhí)行。\

示例代碼:

<?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() 在鎖定時(shí)堵塞,則給 lock 加上 LOCK_NB

?if(flock($fp,LOCK_EX | LOCK_NB))? ?//鎖定當(dāng)前指針

?{

?// 成功取得鎖后,放心處理訂單

?$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 {

?// 如果獲取鎖失敗,馬上進(jìn)入這里執(zhí)行

?echo "{$uniqid} - 系統(tǒng)繁忙,請(qǐng)稍后再試".PHP_EOL;

?}

?fclose($fp);

});

$http->start();


使用 ab 測(cè)試

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


最后給出三種處理方式的測(cè)試結(jié)果比較

redis 事務(wù)方式:

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


經(jīng)測(cè)試結(jié)果對(duì)比,redis 事務(wù)方式優(yōu)于文件排他鎖方式,而文件排他鎖方式中,非阻塞模式優(yōu)于阻塞模式。

以上內(nèi)容希望幫助到大家,了解更多,請(qǐng)點(diǎn)擊:https://www.bilibili.com/video/BV1JV411b742/


作者:程序員安安

鏈接:https://juejin.cn/post/6914099548223143944

來源:掘金

著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。


知識(shí)分享!PHP并發(fā)場景的三種解決方案的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
巴彦县| 杂多县| 鹤岗市| 扶余县| 迁西县| 四会市| 庄浪县| 全椒县| 个旧市| 嵊州市| 丰宁| 安平县| 辽阳县| 滨州市| 稻城县| 商水县| 阜城县| 同仁县| 玉屏| 万荣县| 辽阳县| 清水县| 寻甸| 阜新| 轮台县| 久治县| 新丰县| 滦南县| 修文县| 榆中县| 大荔县| 庄河市| 苍山县| 嘉定区| 刚察县| 固阳县| 苗栗县| 涪陵区| 扎兰屯市| 景德镇市| 伊吾县|