欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品

主頁 > 知識庫 > 淺談并發處理PHP進程間通信之外部介質

淺談并發處理PHP進程間通信之外部介質

熱門標簽:常州地圖標注服務商 福州人工外呼系統哪家強 安裝電銷外呼系統 新河科技智能外呼系統怎么樣 釘釘打卡地圖標注 衡水外呼系統平臺 百度商鋪地圖標注 地圖標注平臺怎么給錢注冊 注冊400電話申請

進程間通信

進程間通信,指至少兩個進程或線程間傳送數據或信號的一些技術或方法。進程是計算機系統分配資源的最小單位(嚴格說來是線程)。每個進程都有自己的一部分獨立的系統資源,彼此是隔離的。為了能使不同的進程互相訪問資源并進行協調工作,才有了進程間通信。

根據定義可知,要進行進程間通信,我們需要解決兩個問題:

  • 互相訪問:消息傳輸和暫時存儲介質選擇問題;
  • 協調工作:消息的存取沖突問題;

文章介紹的中心就是圍繞著這么兩點來說的, 為了更使文章更簡明,這邊以之前在公司做的一個需求為例:

需要一個循環ID生成器,循環生成從 Min 到 Max 的數字ID,在ID遞增到 Max 后,返回到 Min 重新開始遞增;必須能保證多個進程并發請求時生成的ID不同。

此需求要解決的問題恰好為我們要解決的進程間通信需要解決的兩個問題:

  • 需要一個消息傳輸通道來傳輸和存儲當前的遞增值。這個比較容易解決,我們常用的文件、數據庫、session、緩存等都能做到。
  • 需要解決多進程同時訪問生成器生成相同ID的問題。要滿足這個需要就必須要用到鎖了,而且為了保證多個進程讀取的數據是不同的,需要互斥鎖,另外為了能保證調用成功率,鎖的獲取最好能實現自旋。

本文通過此需求的不同實現,來介紹通過外部介質進行的進程間通信的方式。另外,不只PHP語言,其他語言也能使用這些方法。

文件

flock

文件是最基本的存儲介質,它當然可以作為消息的傳輸通道來使用。文件的存取各種語言都有各自的多種方案,問題點是多進程并發時的沖突問題。

解決存取沖突問題我們使用PHP的flock()函數:

bool flock ( resource $handle , int $operation [, int $wouldblock ] )

$handler 是 使用fopen($path_to_file)獲取到的文件句柄;

$operation 是 對文件加鎖的方式,有以下值可選:

LOCK_SH (獲取共享鎖) / LOCK_EX (獲取互斥鎖) / LOCK_UN (解鎖)

這里我們選用互斥鎖,一個進程獲取到互斥鎖后,其他進程在嘗試獲取鎖會被阻塞,直到鎖被釋放,即實現了自旋;

此外,還有一個參數 LOCK_NB,flock 在獲取不到鎖時,默認會阻塞住直到鎖被其他進程釋放,傳入 LOCK_NB 與 LOCK_SH 或 LOCK_EX 進行或運算結果(LOCK_EX | LOCK_NB),flock 在鎖被其他進程占有時,不會阻塞,而是直接返回 false,這里僅作介紹,我們并不使用它。

$wouldblock 參數是一個引用值,在獲取不到鎖,且不阻塞模式時,$wouldblock 會被設置為 true;(手冊中說阻塞時才會被設置為 true。其實我也奇怪這個變量名的。不知道是不是 bug,我的PHP版本是 5.4.5,有知道的煩請解惑)

代碼實現

下面是循環ID生成器代碼,說明在注釋中:

function getCycleIdFromFile($max, $min = 0) {
    $handler = fopen('/tmp/cycle_id_generator.txt', 'c+');
    if (!flock($handler, LOCK_EX)) {
        throw new Exception('error_get_file_lock!');
    }
    
    $cycle_id = trim(fread($handler, 9));
    $cycle_id++;

    if ($cycle_id > $max) {
        $cycle_id = $min;
    }

    // 文件指針返回到文件頭,并向文件內寫入新的cycle_id
    rewind($handler);
    fwrite($handler, $cycle_id);

    // 多寫入一些空格為了防止數值升到多位后,突然置為少位后面的數字仍保留
    fwrite($handler, str_repeat(' ', 9));

    flock($handler, LOCK_UN);

    return $cycle_id;
}

mysql

select for update

我們常用的 mysql 也可以被當作中間介質來實現進程間的通信,我們規定好某一個數據表內的某一行數據作為消息交換的中轉站,使用 mysql 自帶的鎖來協調多個進程的存取沖突。

事務的設計目的就是為了解決多進程并發查詢時數據沖突的問題,可是我們常用的事務只能保證數據沖突時會被回滾,數據不會出現錯誤,并不能實現請求的并行化。對一些數據沖突回滾的請求,需要我們在外層添加邏輯重試。

這里介紹 mysql 的一種語法: select for update,會給固定數據加上互斥鎖,且另一個請求在獲取鎖失敗時,會阻塞至獲取鎖成功,mysql 幫我們實現了自旋;

用法如下:

1.關閉 mysql 的自動提交,自動提交默認打開,除非使用 transition 語句顯示開啟事務,默認會將每一條 sql 作為一個事務直接提交執行,這里關閉。 set autocommit=0;

2.使用select for update 語句給數據添加互斥鎖。注意:需求 mysql 的 innodb 引擎支持;

3.進行數據更新和處理操作;

4.主動提交事務,并將 自動提交恢復;commit; set autocommit=1;

代碼實現

然后是代碼實現:

// 數據庫連接實現各有不同,demo 可以自己修改一下。
function getCycleIdFromMysql($max, $min = 0){
    Db::db()->execute('set autocommit = 0');
    $res = Db::db()->qsqlone('SELECT cycle_id FROM cycle_id_generator WHERE id = 1 FOR UPDATE');

    $cycle_id = $res['cycle_id'] + 1;
    if($cycle_id > $max){
        $cycle_id = $min;
    }

    Db::db()->execute("UPDATE cycle_id_generator SET cycle_id = {$cycle_id} WHERE id = 1");

    Db::db()->execute('commit');
    Db::db()->execute('set autocommit = 1');

    return $cycle_id;
}

redis

incr

redis 是我們常用的緩存服務器,由于其使用內存存儲數據,性能很高。我們使用一個固定的普通鍵來作為消息中轉站,然后利用其incr命令的原子性和其執行結果(遞增后的值),實現 cycle_id 的遞增。

incr(key) 若 key 不存在,redis 會先將值設置為0,然后執行遞增操作;

遞增沒有問題,可是我們還有個需求是在要其值達到 max 時,再將其置為 min,這時就可能會出現進程A在更新值為 min 時,另一個進程B也檢測到值大于了 max,然后將值置為 min,可是這時的值已經不是 max,即發生了值重復更新,那么返回的值必然會有重復;

這時,我們就需要自己來實現鎖了。

SETNX

redis 的 SETNX 命令檢測某一個 key 是否存在,若不存在,則將 key 的值設置為 value,并返回結果1; 若 key 已存在,則設置失敗,返回值0。

SETNX key value

它能實現鎖是因為它是一個原子命令,即 檢測 key 是否存在和設置 key 值在一個事務內,不會出現同時兩個進程都檢測到 key 不存在,然后同時去設置 key 的情況。

我們以另一個值的存在與否,來表示 cycle_id 是否正在被另一個進程修改。

代碼實現

 function getCycleIdFromRedis($max, $min = 0) {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $key_id = 'cycle_id_generator';

    $cycle_id = $redis->incr($key_id);
    
    if ($cycle_id > $max) {
        // 設置"鎖鍵"的結果 = 獲取互斥結果
        $key_lock = 'cycle_id_lock';
        if (!$redis->setnx($key_lock, 1)) {
            return null;
        }

        $cycle_id = $min;
        $redis->set($key_id, $cycle_id);

        // 最后別忘記釋放互斥鎖
        $redis->delete($key_lock);
    }

    $redis->close();

    return $cycle_id;
}

注意:由于 redis 里沒有能實現自旋鎖的命令,如果需求最高的獲取成功率,我們在檢測到 cycle_id 已經是最大值,且試圖修改獲取鎖失敗時,退出重試,在外層進行重試。

function getCycleId($max, $min = 0) {
    $cycle_id = getCycleIdFromRedis($max, $min);
    if (!is_null($cycle_id)) {
        return $cycle_id;
    }
    // 稍微等待下正在更改的進程
    usleep(500);
    // 這里使用遞歸,直至獲取成功  并發很高,cycle_id重置很頻繁時慎用.
    return getCycleId($max, $min);
}

優化

審查代碼我們會發現,如果 max-min 的值很小的話,redis 會需要經常重置 key 的值,也就經常需要加鎖,重試也就很多。這里,我提供一個優化方法:

我們將其 max 設置為一個很大的值(要能被 max-min 整除),返回值時稍做處理,返回 $current % ($max - $min) + $min;。這樣,key 需要遞增到一個很大的值才會被重置,加鎖邏輯和外層邏輯會很少執行到,達到提升效率的目的。

總結

這里簡單的評價一下上面所說的三種方法:

性能上沒有測試,而且 redis 的性能跟 ID 的大小差值相關,不過猜測在ID大小差值大的情況下 redis 應該更好一點。

代碼上非常直觀,使用 mysql 非常簡潔,而且 redis 要自己實現自旋,比較惡心。

實現上,當然是文件最為方便,無任何添加。

以上就是淺談并發處理PHP進程間通信之外部介質的詳細內容,更多關于并發處理PHP進程間通信之外部介質的資料請關注腳本之家其它相關文章!

您可能感興趣的文章:
  • PHP下用Swoole實現Actor并發模型的方法
  • 淺談并發處理PHP進程間通信之System V IPC
  • PHP+Redis鏈表解決高并發下商品超賣問題(實現原理及步驟)
  • 詳解PHP中curl_multi并發的實現
  • php多進程并發編程防止出現僵尸進程的方法分析
  • PHP高并發和大流量解決方案整理
  • PHP 并發場景的幾種解決方案
  • php多進程模擬并發事務產生的問題小結
  • 淺談Swoole并發編程的魅力

標簽:鶴崗 遼陽 鷹潭 六安 柳州 克拉瑪依 唐山 白城

巨人網絡通訊聲明:本文標題《淺談并發處理PHP進程間通信之外部介質》,本文關鍵詞  淺談,并發,處理,PHP,進程,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《淺談并發處理PHP進程間通信之外部介質》相關的同類信息!
  • 本頁收集關于淺談并發處理PHP進程間通信之外部介質的相關信息資訊供網民參考!
  • 推薦文章
    欧美阿v视频在线大全_亚洲欧美中文日韩V在线观看_www性欧美日韩欧美91_亚洲欧美日韩久久精品
  • <rt id="w000q"><acronym id="w000q"></acronym></rt>
  • <abbr id="w000q"></abbr>
    <rt id="w000q"></rt>
    亚洲色图欧洲色图| 久草在线在线精品观看| 岛国精品一区二区| 泷泽萝拉在线播放| 欧美色精品在线视频| 亚洲美女偷拍久久| www.日韩在线| 色哟哟在线观看一区二区三区| 精品国产免费一区二区三区四区 | 欧美私人免费视频| 亚洲日本在线a| 99久久免费精品高清特色大片| 懂色av蜜臀av粉嫩av永久| 久久影音资源网| 精品一区二区在线观看| japanese中文字幕| 亚洲精品一区二区三区精华液| 日本欧美加勒比视频| 亚洲综合自拍网| 制服丝袜中文字幕一区| 日韩高清不卡在线| 中文字幕第3页| 日韩美一区二区三区| 老司机精品视频线观看86| 制服 丝袜 综合 日韩 欧美| 久久久精品一品道一区| 国产一区不卡精品| 免费一级特黄3大片视频| 国产欧美精品一区| 东方aⅴ免费观看久久av| 色综合久久88色综合天天免费| 亚洲欧美激情一区二区| 一级黄色电影片| 欧美变态tickling挠脚心| 韩国v欧美v日本v亚洲v| 精品人妻伦九区久久aaa片| 亚洲丝袜自拍清纯另类| 95视频在线观看| 欧美日韩中文字幕一区二区| 亚洲gay无套男同| 18禁裸乳无遮挡啪啪无码免费| 欧美成人精精品一区二区频| 国产综合成人久久大片91| 亚洲国产123| 亚洲精品一二三区| 可以看的av网址| 日韩美女主播在线视频一区二区三区| 国产精品中文欧美| 欧美自拍偷拍午夜视频| 日韩高清欧美激情| 91狠狠综合久久久| 亚洲高清免费视频| 国产又黄又粗的视频| 亚洲欧美激情小说另类| 免费a在线观看播放| 国产精品嫩草99a| 韩国三级视频在线观看| 久久综合色天天久久综合图片| 成人免费电影视频| 欧美乱熟臀69xxxxxx| 狠狠色丁香婷婷综合| 破处女黄色一级片| 日韩一区精品字幕| 久久高清内射无套| 免费成人在线视频观看| 色偷偷久久一区二区三区| 免费观看在线色综合| 色综合久久久久久久久| 青娱乐精品在线视频| 国产精品老熟女一区二区| 日本美女视频一区二区| 一区二区在线观看免费视频| 蜜臀av一区二区在线免费观看| 三级影片在线看| 热久久久久久久| 在线观看一区不卡| 国产一区二区网址| 在线播放中文字幕一区| 成人免费的视频| 精品国产一区二区三区忘忧草| 丰满人妻一区二区三区53视频| 久久综合色一综合色88| 日韩成人av影院| 国产精品久久久久久久久免费桃花| 亚洲国产精品狼友在线观看| 中文子幕无线码一区tr| 国产呦小j女精品视频| 亚洲乱码国产乱码精品精98午夜 | 网站免费在线观看| 亚洲天堂精品在线观看| 国内精品卡一卡二卡三| 午夜精品久久久久久| 成人观看免费视频| 国产美女视频一区| 日韩一区二区中文字幕| 91女神在线视频| 国产精品污污网站在线观看| 中文字幕一区二区久久人妻网站 | 久久人妻无码aⅴ毛片a片app| 日本欧美在线观看| 欧美性猛交xxxx乱大交退制版| 国产激情视频一区二区在线观看 | 91精品免费观看| 91在线国产观看| 国产精品私人自拍| 神马久久久久久久久久久| 欧美aaaaaa午夜精品| 正在播放一区二区| gogo亚洲国模私拍人体| 《视频一区视频二区| 亚洲欧美精品aaaaaa片| 国产久卡久卡久卡久卡视频精品| 日韩精品一区二区三区在线| 在线免费看黄色片| 亚洲国产精品影院| 色天天综合久久久久综合片| 国产激情一区二区三区四区| 国产网红主播福利一区二区| 一区二区在线观看视频在线观看| 四虎永久免费地址| 国产乱人伦偷精品视频免下载| 精品成a人在线观看| 亚洲最大成人网站| 蜜桃视频在线一区| 欧美变态凌虐bdsm| 欧洲av一区二区三区| 久久www免费人成看片高清| 日韩精品一区在线观看| 成人精品999| 久久精品免费看| 精品国产乱码久久久久久影片| 久久精品国产亚洲av麻豆| 热久久久久久久| xnxx国产精品| 国产视频123区| 国产91精品免费| 日韩理论在线观看| 91久久精品一区二区二区| 国产老头和老头xxxx×| 亚洲精品国产高清久久伦理二区| 在线免费观看一区| 精品国产免费久久久久久婷婷| 香港成人在线视频| 日韩你懂的在线观看| 亚洲综合色一区| 国产一区二区三区四区在线观看| 日本一区二区视频在线观看| 成年人一级黄色片| a级大片免费看| 性久久久久久久| 欧美精品一区二区不卡| 国产3级在线观看| 99久久精品国产一区| 亚洲国产成人91porn| 日韩欧美国产一区二区三区| 久久久精品成人| 成人91在线观看| 亚洲一二三四区不卡| 日韩欧美一区二区久久婷婷| аⅴ天堂中文在线网| www.在线欧美| 亚洲图片欧美视频| 精品国产免费人成在线观看| 永久久久久久久| 国产原创剧情av| 狠狠色丁香婷综合久久| 亚洲免费在线播放| 91精品国产欧美一区二区成人| 人人爽人人爽人人片| a级精品国产片在线观看| 香蕉成人啪国产精品视频综合网 | 亚洲国产美女视频| 欧美午夜精品一区二区| 免费不卡在线视频| 国产精品麻豆99久久久久久| 欧美日本视频在线| 人妻少妇无码精品视频区| 99久久久久久| 日韩av电影免费观看高清完整版| 国产欧美日韩另类视频免费观看| 色88888久久久久久影院按摩| 捆绑裸体绳奴bdsm亚洲| 国产91综合一区在线观看| 亚洲一区二区三区影院| 久久嫩草精品久久久精品一| 在线免费观看日韩欧美| 91资源在线播放| 野花视频免费在线观看| 黄网站免费久久| 亚洲一区视频在线| 久久精品日产第一区二区三区高清版| 一本一道久久a久久精品| 亚洲熟妇一区二区三区| 暴力调教一区二区三区| 麻豆一区二区在线| 国产精品乱码久久久久久| 日韩欧美国产电影| 天堂av网手机版| 欧美图片自拍偷拍| 国产精品自产自拍|