多執行緒程式設計 PHP 實現

2021-09-30 16:42:27 字數 3670 閱讀 3679

前些天幫同事查乙個問題,第一次接觸到了 php 的多執行緒,原以為 php 普遍都是單執行緒模型,並不適合多執行緒領域,花些時間翻了幾個多執行緒的專案原始碼之後,發現 php 的多執行緒也頗有可取之處,活用起來,用來解決某些問題竟然非常適合。

於是找了幾篇文章看了下 php 多執行緒tsrm機制的實現,也有所收穫,詳情可以檢視下面的參考文章。本文對比多程序介紹了下多執行緒的優勢和適用場景,提出了一種巧用方案,並使用 php **實現了多執行緒的常見用法。

首先說下執行緒:

執行緒(thread) 是作業系統能夠進行運算排程的最小單位。它被包含在程序之中,是程序中的實際運作單位。一條執行緒指的是程序中乙個單一順序的控制流,乙個程序中可以併發多個執行緒,每條執行緒並行執行不同的任務.

使用多執行緒主要是因為它在執行效率上有很大優勢。由於執行緒是作業系統能夠進行排程的最小單位

同時對比多程序程式,多執行緒有以下特點:

多執行緒的優化是很多,可是無腦使用多執行緒並不能提公升程式的執行效率,因為執行緒的建立和銷毀、上下文切換、執行緒同步等也是有效能損耗的,耗費時間可能比順序執行的**還多。如:

sumsmall是乙個從1累加到50000的函式。

上圖是在主線程內執行了三次 sumsmall 和三個執行緒分別執行 sumsmall ,再將結果同步到乙個執行緒的時間對比,我們會發現只在主線程執行的時間反而更短,三個執行緒建立、切換、同步的時間遠遠大過了執行緒非同步執行節省的時間。

而函式 sumlarge 從1累加到5000000,下圖同一執行緒執行三次和三個執行緒執行的耗時:

這次,多執行緒終於有效率優勢了。

是否使用多執行緒還需要根據具體需求而定,一般考慮以下兩種情況:

php 預設並不支援多執行緒,要使用多執行緒需要安裝 pthread 擴充套件,而要安裝 pthread 擴充套件,必須使用--enable-maintainer-zts引數重新編譯 php,這個引數是指定編譯 php 時使用執行緒安全方式。

多執行緒是讓程式變得不安分的乙個因素,在使用多執行緒之前,首先要考慮執行緒安全問題:

執行緒安全:執行緒安全是程式設計中的術語,指某個函式、函式庫在多執行緒環境中被呼叫時,能夠正確地處理多個執行緒之間的共享變數,使程式功能正確完成。

在傳統多執行緒中,由於多個執行緒共享變數,所以可能會導致出現如下問題:

存在乙個全域性陣列$arr = array('a');;

a 執行緒獲取陣列長度為1;

b 執行緒獲取陣列長度為1;

a 執行緒 pop 出陣列元素$a = array_pop($arr); $a = 'a';;

b 執行緒也 pop 陣列元素$b = array_pop($arr); $a = null;;

此時 b 執行緒內就出現了靈異事件,明明陣列長度大於0,或沒有 pop 出東西;

php 實現的執行緒安全主要是使用tsrm機制對全域性變數和靜態變數進行了隔離,將全域性變數和靜態變數 給每個執行緒都複製了乙份,各執行緒使用的都是主線程的乙個備份,從而避免了變數衝突,也就不會出現執行緒安全問題。

php 對多執行緒的封裝保證了執行緒安全,程式設計師不用考慮對全域性變數加各種鎖來避免讀寫衝突了,同時也減少了出錯的機會,寫出的**更加安全。

但由此導致的是,子執行緒一旦開始執行,主線程便無法再對子執行緒執行細節進行調整了,執行緒一定程度上失去了執行緒之間通過全域性變數進行訊息傳遞的能力。

同時 php 開啟執行緒安全選項後,使用tsrm機制分配和使用變數時也會有額外的損耗,所以在不需要多執行緒的 php 環境中,使用 php 的 zts (非執行緒安全) 版本就好。

php 將執行緒 封裝成了thread類,執行緒的建立通過例項化乙個執行緒物件來實現,由於類的封裝性,變數的使用只能通過建構函式傳入,而執行緒運算結果也需要通過類變數傳出。

下面介紹幾個常用的 thread 類方法:

因為執行緒安全的實現,php 的多執行緒開始執行後,無法再通過共享記憶體空間通訊,執行緒也無法通過執行緒間通訊復用,所以我認為 php 的「執行緒池」並沒有什麼意義。擴充套件內自帶的pool類是乙個對多執行緒分配管理的類,這裡也不再多介紹了。

下面是乙個執行緒類,用來請求某一介面。接下來根據它寫兩個多執行緒的應用例項:

class request extends thread 

public function run()

}

將同步的請求拆分為多個執行緒非同步呼叫,以提公升程式的執行效率。

我們在使用 curl 請求某個位址時,可以通過curlopt_connecttimeout / curlopt_timeout引數分別設定 curl 的連線超時時間和讀取資料超時時間,但總的超時時間不好控制。而且在進行資料庫查詢時的超時時間無法設定(鳥哥部落格:為mysql設定查詢超時)。

這時我們便可以借用多執行緒來實現此功能:在執行執行緒類的start()方法後,不呼叫join()方法,使執行緒一直處於非同步狀態,不阻塞主線程的執行。

此時主線程相當於旗艦,而各子執行緒相當於巡航艦,旗艦到達某地後不必要一直等待巡航艦也歸來,等待一段時間後離開即可,從而避免巡航艦意外時旗艦白白空等。

// 此處不對chg執行join方法

sleep(1); // sleep乙個能接受的超時時間

$gl = $chg->response;

$bd = $chb->response;

$bd->kill();

if (!$gl)

php 對多執行緒進行的封(yan)裝(ge),讓人用執行緒用得非常不盡興。雖然安全,也保持 php 簡單易用的一貫風格,卻無法完全發揮多執行緒的能力。不過各個語言各有特色和側重點,也不必強求,愛她就要包容她 =_=。

最近在重學作業系統和 linux 核心方面的知識,對程式的認知有了很大提公升,感覺非常有必要總結一下,敬請期待。

支援一下我,部落格一直在更新,歡迎關注

參考:深入研究php及zend engine的執行緒安全模型

php高階程式設計之多執行緒

PHP多執行緒的實現(PHP多執行緒類)

通過web伺服器來實現php多執行緒功能。當然,對多執行緒有深入理解的人都知道通過web伺服器實現的多執行緒只能模仿多執行緒的一些效果,並不是真正意義上的多執行緒。但不管怎麼樣,它還是能滿足我們的一些需要的,在需要類似多執行緒的功能方面還是可以採用這個類。view source print?01.0...

php 開啟多執行緒 php如何實現多執行緒

php中可以實現多執行緒,是一種利用舊的exec函式通過非同步處理方法實現多執行緒的,exec函式本身就是乙個執行外部程式的php函式。下面我們就來具體看看php多執行緒的實現方法。我們首先來看乙個示例 class execmulti function multithreadtest exec ph...

PHP實現多執行緒讀寫檔案

123 4const max retries 100 最大重試數,此處注意,const變數不能寫在function內56 7 param file path 檔案路徑 8 param file mode 開啟檔案模式 eg r,r w,w a,a x,x 9 param lock mode 加鎖模式...