婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > 淺談并發處理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進程間通信之外部介質的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    欧美人狂配大交3d怪物一区| 久久色.com| 五月天激情综合| 91美女在线看| 亚洲成av人片一区二区三区| 精品福利二区三区| 99re这里只有精品6| 麻豆国产精品一区二区三区| 1024精品合集| 久久亚区不卡日本| 欧美精品在线观看播放| 国产精品久久久久久久第一福利 | 日韩丝袜美女视频| 日本韩国一区二区三区视频| 国产成人综合网站| 国产精品福利av| 精品国内片67194| 欧美军同video69gay| 色婷婷综合激情| 大尺度一区二区| 欧美国产丝袜视频| 国产精品一线二线三线| 秋霞影院一区二区| 亚洲综合一区二区精品导航| 亚洲欧美综合网| 亚洲综合在线第一页| 欧美日韩一区二区在线观看视频| 香蕉加勒比综合久久| 精品裸体舞一区二区三区| 美国欧美日韩国产在线播放| 国产三级精品在线| 亚洲人吸女人奶水| 91精品久久久久久蜜臀| 国产在线播放一区三区四| 中文字幕一区在线观看视频| 午夜欧美视频在线观看 | 国产精品亚洲成人| 一区二区三区国产精华| 精品国产91九色蝌蚪| 色综合天天狠狠| 久久国产精品一区二区| 自拍视频在线观看一区二区| 51午夜精品国产| proumb性欧美在线观看| 日韩电影一区二区三区四区| 国产精品麻豆欧美日韩ww| 欧美日韩国产大片| 成人动漫视频在线| 久久 天天综合| 亚洲国产一区视频| 国产精品二区一区二区aⅴ污介绍| 欧美精品一级二级三级| 99久久免费国产| 国产精品一级在线| 久久精品国产久精国产爱| 精一区二区三区| 欧美一卡二卡三卡四卡| 麻豆久久久久久| 久久精品日产第一区二区三区高清版 | 99视频超级精品| www.欧美.com| 欧美日韩亚洲高清一区二区| 91蜜桃免费观看视频| 久久久久久久久蜜桃| www国产成人| 亚洲美腿欧美偷拍| 午夜国产不卡在线观看视频| 青青草97国产精品免费观看 | 久久久精品黄色| 一区二区三区视频在线观看| 麻豆久久一区二区| 成人黄色免费短视频| 制服丝袜国产精品| 亚洲视频免费观看| 另类调教123区 | 欧美精品丝袜久久久中文字幕| 日韩成人一级大片| 国产精品国产三级国产专播品爱网| 成人黄色国产精品网站大全在线免费观看 | 欧美酷刑日本凌虐凌虐| 欧美精品一区二区三| 亚洲国产日韩精品| 国产69精品一区二区亚洲孕妇| 在线观看亚洲一区| 亚洲欧洲另类国产综合| 天天av天天翘天天综合网色鬼国产| 午夜久久久影院| 国产高清成人在线| 1024成人网色www| 亚洲第四色夜色| caoporm超碰国产精品| 国产成人综合在线播放| 91久久精品一区二区| 亚洲同性同志一二三专区| 欧美国产成人在线| 国产在线播放一区三区四| 国产精品1区二区.| 丁香一区二区三区| 国产精品亚洲第一区在线暖暖韩国| 亚洲欧美日韩国产手机在线| 久久综合精品国产一区二区三区 | 一区二区三区四区国产精品| 亚洲乱码国产乱码精品精小说| 国产精品免费aⅴ片在线观看| 日韩一区二区三区免费观看| 欧美日韩高清一区二区三区| 国产**成人网毛片九色| 国产高清无密码一区二区三区| 亚洲一区二区三区在线播放| 日本午夜精品一区二区三区电影| 欧美伦理影视网| 天堂精品中文字幕在线| 欧美videofree性高清杂交| 亚洲电影你懂得| 色噜噜狠狠色综合欧洲selulu| 亚洲黄色在线视频| 在线视频国内一区二区| 欧美激情一区二区三区全黄 | 麻豆成人av在线| 欧美一级精品大片| 亚洲综合色视频| 老司机免费视频一区二区三区| 91在线免费视频观看| 精品国产乱码久久久久久1区2区| 蜜乳av一区二区三区| 91福利视频久久久久| 视频精品一区二区| 色8久久人人97超碰香蕉987| 久久久一区二区三区捆绑**| 亚洲成av人综合在线观看| 狠狠色丁香婷婷综合| 岛国精品在线观看| 亚洲乱码中文字幕| 亚洲一区二区综合| 精品国精品国产| 欧美r级电影在线观看| 欧美一区二区大片| 亚洲欧美一区二区三区久本道91| 欧美在线观看18| 国产精品美女久久久久久2018| 亚洲小说春色综合另类电影| 亚洲乱码精品一二三四区日韩在线| 91网上在线视频| 天天色图综合网| 欧美视频三区在线播放| 久久久精品黄色| 麻豆成人综合网| 91搞黄在线观看| 亚洲成人午夜影院| 91麻豆精品国产综合久久久久久| 一级特黄大欧美久久久| 欧美日韩在线亚洲一区蜜芽| 日韩国产一区二| 国产人妖乱国产精品人妖| 丝袜美腿亚洲综合| 欧美性色欧美a在线播放| 香蕉久久夜色精品国产使用方法| 欧美人xxxx| 国产美女精品一区二区三区| 亚洲女子a中天字幕| 成人av中文字幕| 五月激情丁香一区二区三区| 久久久久九九视频| 久久久激情视频| 日韩欧美激情四射| 99久久精品国产精品久久| 久久99精品视频| 亚洲天堂久久久久久久| 波多野结衣的一区二区三区| 99久久国产综合精品色伊| 国产在线看一区| 国产精品资源在线看| 国产成人综合亚洲91猫咪| 午夜精品免费在线| 欧美三级电影网站| 久久精品免费看| 国产精品拍天天在线| 91亚洲精品一区二区乱码| 亚洲国产精品一区二区久久恐怖片| 精品美女在线观看| 91精品国产综合久久香蕉麻豆| 国产精品一区三区| 亚洲久草在线视频| 国产精品一区2区| 国产精品乱码人人做人人爱| 91视频免费播放| 精品一区二区av| 午夜精品一区二区三区三上悠亚| 国产日韩欧美精品综合| 日韩欧美视频在线| 欧美日韩一区不卡| 欧美在线观看一二区| 亚洲欧美日韩一区二区三区在线观看| 久久亚洲免费视频| 91精品婷婷国产综合久久竹菊| 99精品视频在线观看| 日韩av一区二区三区| 一区二区高清免费观看影视大全| 亚洲国产高清在线| 久久亚洲精品国产精品紫薇|