在PHP領域,多執行緒的概念並不像其他語言那麼為人所知。本以為PHP 一般都是單執行緒模型,並不適合多執行緒領域。在翻了一些多線程的專案原始碼之後,發現 PHP 的多線程也有不過的用處。活用起來,用來解決某些問題竟然非常適合。
多執行緒
執行緒
首先說下執行緒:
#執行緒(thread) 是作業系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以並發多個線程,每條線程並行執行不同的任務.
使用多線程主要是因為它在執行效率上有很大優勢。由於執行緒是作業系統能夠進行調度的最小單位:
一個多執行緒程式比單執行緒程式被作業系統調度的機率更大,所以多執行緒程式一般會比單執行緒程式更有效率;
多執行緒程式的多個執行緒可以在多核心CPU 的多個核心同時運行,可以將完全發揮機器多核心的優勢;
同時對比多進程程序,多執行緒有以下特點:
線程的創建和切換的系統開銷都比進程要小,所以一定程度上會比多進程更有效率;
線程天生的共享記憶體空間,線程間的通訊更簡單,避免了進程IPC引進新的複雜度。
適用場景
多執行緒的最佳化是很多,可是無腦使用多執行緒並不能提升程式的執行效率,因為執行緒的建立與銷毀、上下文切換、執行緒同步等也是有效能損耗的,耗費時間可能比順序執行的程式碼還多。如:
sumSmall是一個從1累加到50000的函數。
上圖是在主執行緒內執行了三次sumSmall 和三個執行緒分別執行sumSmall ,再將結果同步到一個執行緒的時間對比,我們會發現只在主執行緒執行的時間反而更短,三個執行緒創建、切換、同步的時間遠遠大過了執行緒非同步執行節省的時間。
而函數sumLarge 從1累加到5000000,下圖同一執行緒執行三次和三個執行緒執行的耗時:
這次,多執行緒終於有效率優勢了。
是否使用多執行緒還需要根據具體需求而定,一般考慮以下兩種情況:
I/O 阻塞會使作業系統發生任務調度,阻塞目前任務,所以程式碼中I/O 多的情況下,使用多執行緒時可以將程式碼並行。例如多次讀取整塊的文件,或請求多個網路資源。
多執行緒能充分利用 CPU,所以當多處大運算量程式碼時,也可以使用多執行緒讓他們並行執行,例如上文中後一個範例。
PHP中的多線程
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 實作
PHP 實作的執行緒安全性主要是使用TSRM 機制對全域變數和靜態變數進行了隔離,將全域變數和靜態變數給每個執行緒都複製了一份,各執行緒使用的都是主執行緒的一個備份,從而避免了變數衝突,也就不會出現執行緒安全性問題。
PHP 對多執行緒的封裝保證了執行緒安全,程式設計師不用考慮對全域變數加各種鎖來避免讀寫衝突了,同時也減少了出錯的機會,寫出的程式碼更加安全。
但由此導致的是,子執行緒一旦開始運行,主執行緒便無法再對子執行緒運行細節進行調整了,執行緒一定程度上失去了執行緒之間透過全域變數進行訊息傳遞的能力。
同時PHP 開啟執行緒安全選項後,使用TSRM 機制指派和使用變數時也會有額外的損耗,所以在不需要多執行緒的PHP 環境中,使用PHP 的ZTS (非執行緒安全性) 版本就好。
類別和方法
PHP 將執行緒封裝成了Thread 類,執行緒的建立透過實例化一個執行緒物件來實現,由於類別的封裝性,變數的使用只能透過建構函式傳入,而執行緒運算結果也需要透過類別變數傳出。
下面介紹幾個常用的Thread 類別方法:
run():此方法是一个抽象方法,每个线程都要实现此方法,线程开始运行后,此方法中的代码会自动执行; start():在主线程内调用此方法以开始运行一个线程; join():各个线程相对于主线程都是异步执行,调用此方法会等待线程执行结束; kill():强制线程结束; isRunning():返回线程的运行状态,线程正在执行run()方法的代码时会返回 true;
因為線程安全的實現,PHP 的多線程開始運行後,無法再通過共享內存空間通信,線程也無法通過線程間通訊復用,所以我認為PHP 的「線程池」並沒有什麼意義。擴充內自帶的Pool 類別是一個對多執行緒分配管理的類,這裡也不再多介紹了。
實例程式碼
下面是一個執行緒類,用來請求某一介面。接下來根據它寫兩個多執行緒的應用實例:
class Request extends Thread { public $url; public $response; public function __construct($url) { $this->url = $url; } public function run() { $this->response = file_get_contents($this->url); } }
非同步請求
將同步的請求拆分為多個執行緒非同步調用,以提升程式的運作效率。
$chG = new Request("www.google.com"); $chB = new Request("www.baidu.com"); $chG ->start(); $chB ->start(); $chG->join(); $chB->join(); $gl = $chG->response; $bd = $chB->response;
超時控制
偶然間發現公司網站某一網頁上的一塊內容時有時無,不知道具體實現,但這給了我使用多線程的靈感:利用線程異步實現快速失敗和超時控制。
我們在使用 curl 請求某個位址時,可以透過 CURLOPT_CONNECTTIMEOUT / CURLOPT_TIMEOUT 參數分別設定 curl 的連線逾時時間和讀取資料逾時時間,但總的逾時時間不好控制。而且在進行資料庫查詢時的逾時時間無法設定(鳥哥部落格:為MySQL設定查詢逾時)。
這時我們便可以藉用多執行緒來實作此功能:執行執行緒類別的start() 方法後,不呼叫join() 方法,讓執行緒一直處於非同步狀態,不阻塞主執行緒的執行。
此時主線程相當於旗艦,而各子線程相當於巡航艦,旗艦到達某地後不必要一直等待巡航艦也歸來,等待一段時間後離開即可,從而避免巡航艦意外時旗艦白白空等。
程式碼:
$chG = new Request("www.google.com"); $chB = new Request("www.baidu.com"); $chG->start(); $chB->start(); $chB->join(); // 此处不对chG执行join方法 sleep(1); // sleep一个能接受的超时时间 $gl = $chG->response; $bd = $chB->response; $bd->kill(); if (!$gl) { $gl = ""; // 处理异常,或在线程类内给$gl一个默认值 }
總結
PHP 對多執行緒進行的封(yan)裝(ge),讓人用執行緒用得非常不盡興。雖然安全,也保持 PHP 簡單易用的一貫風格,卻無法完全發揮多執行緒的能力。不過各個語言各有特色和重點,也不必強求,愛她就要包容她 =_=。
相關推薦:
#以上是PHP對多執行緒程式設計的支援以及使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

在PHP中,可以使用session_status()或session_id()來檢查會話是否已啟動。 1)使用session_status()函數,如果返回PHP_SESSION_ACTIVE,則會話已啟動。 2)使用session_id()函數,如果返回非空字符串,則會話已啟動。這兩種方法都能有效地檢查會話狀態,選擇使用哪種方法取決於PHP版本和個人偏好。

sessionsarevitalinwebapplications,尤其是在commercePlatform之前。

在PHP中管理並發會話訪問可以通過以下方法:1.使用數據庫存儲會話數據,2.採用Redis或Memcached,3.實施會話鎖定策略。這些方法有助於確保數據一致性和提高並發性能。

PHPsessionshaveseverallimitations:1)Storageconstraintscanleadtoperformanceissues;2)Securityvulnerabilitieslikesessionfixationattacksexist;3)Scalabilityischallengingduetoserver-specificstorage;4)Sessionexpirationmanagementcanbeproblematic;5)Datapersis

負載均衡會影響會話管理,但可以通過會話複製、會話粘性和集中式會話存儲解決。 1.會話複製在服務器間複製會話數據。 2.會話粘性將用戶請求定向到同一服務器。 3.集中式會話存儲使用獨立服務器如Redis存儲會話數據,確保數據共享。

Sessionlockingisatechniqueusedtoensureauser'ssessionremainsexclusivetooneuseratatime.Itiscrucialforpreventingdatacorruptionandsecuritybreachesinmulti-userapplications.Sessionlockingisimplementedusingserver-sidelockingmechanisms,suchasReentrantLockinJ

PHP會話的替代方案包括Cookies、Token-basedAuthentication、Database-basedSessions和Redis/Memcached。 1.Cookies通過在客戶端存儲數據來管理會話,簡單但安全性低。 2.Token-basedAuthentication使用令牌驗證用戶,安全性高但需額外邏輯。 3.Database-basedSessions將數據存儲在數據庫中,擴展性好但可能影響性能。 4.Redis/Memcached使用分佈式緩存提高性能和擴展性,但需額外配

Sessionhijacking是指攻擊者通過獲取用戶的sessionID來冒充用戶。防範方法包括:1)使用HTTPS加密通信;2)驗證sessionID的來源;3)使用安全的sessionID生成算法;4)定期更新sessionID。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

Atom編輯器mac版下載
最受歡迎的的開源編輯器

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

禪工作室 13.0.1
強大的PHP整合開發環境

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能