pthreads 是一組允許用戶(hù)在 PHP 中使用多線(xiàn)程技術(shù)的面向對象的 API。 它提供了創(chuàng )建多線(xiàn)程應用所需的全套工具。 通過(guò)使用 Thread, Worker 以及 Threaded 對象,PHP 應用可以創(chuàng )建、讀取、寫(xiě)入以及執行多線(xiàn)程應用,并可以在多個(gè)線(xiàn)程之間進(jìn)行同步控制。
此擴展已被聲明為停止維護狀態(tài)。
建議使用 parallel 作為替代。
不可以在 web 服務(wù)器環(huán)境中使用 pthreads 擴展, PHP 多線(xiàn)程開(kāi)發(fā)僅限于命令行模式的應用。
只能在 PHP 7.2+ 版本中使用 pthreads (v3) 擴展, 在 PHP 7.0 和 7.1 版本中,ZTS 模式是不安全的。
Threaded 對象: Threaded 對象提供支持 pthreads 操作的基本功能,包括同步方法以及其他對程序員很有幫助的接口。
Thread 對象:
通過(guò)繼承 pthreads 中提供的 Thread 對象并實(shí)現 run
方法,用戶(hù)可以創(chuàng )建自己的 Thread 對象。
只要線(xiàn)程上下文中持有某個(gè) Thread 對象的引用,就可以讀/寫(xiě)該對象的屬性,也可以調用該對象的公有(public)或者受保護(protected)的方法。
當在創(chuàng )建 Thread 對象的上下文中調用該對象的 Thread::start() 方法時(shí),pthreads 擴展會(huì )在另外的獨立線(xiàn)程中執行該對象的 run 方法。
僅有創(chuàng )建 Thread 對象的線(xiàn)程/進(jìn)程方可開(kāi)始(start)或者加入(join)這個(gè) Thread 對象。
Worker 對象:
Worker 是有狀態(tài)的線(xiàn)程對象,它在線(xiàn)程開(kāi)始(通過(guò)調用 Thread::start() 方法)之后就可用,
除非代碼中顯式地關(guān)閉線(xiàn)程(通過(guò)調用 Worker::shutdown() 方法),
否則該對象在線(xiàn)程對象超出作用范圍之后才會(huì )失效。
持有 Worker 對象引用的線(xiàn)程上下文可以向 Worker 中入棧(通過(guò)調用 Worker::stack() 方法)其他線(xiàn)程對象,Worker 對象將在獨立線(xiàn)程中執行入棧對象的代碼。
Woker 對象的 run
方法會(huì )在它的棧中入棧對象之前執行,這樣就可以進(jìn)行一些必需的資源初始化工作。
Pool 對象: Pool 對象是 Worker 線(xiàn)程對象池,可以用來(lái)在多個(gè) Worker 對象之間分發(fā) Threaded 對象, 這是最易用且高效的多線(xiàn)程編程方式。
Volatile 類(lèi)是在 pthreads v3 中新增加的, 用來(lái)表示可變的 Threaded 類(lèi)中的 Threaded 屬性(默認情況下是不可變的)。 它也可以被用來(lái)在 Threaded 上下文中存儲數組。
線(xiàn)程間同步: 由 pthreads 擴展創(chuàng )建的所有對象擁有內置的線(xiàn)程間同步機制, 和 Java 語(yǔ)言很類(lèi)似, 使用 Threaded::wait() 和 Threaded::notify() 方法來(lái)實(shí)現線(xiàn)程間同步。 調用某一個(gè)對象的 Threaded::wait() 方法 會(huì )導致當前線(xiàn)程上下文進(jìn)入等待狀態(tài), 等待另外一個(gè)線(xiàn)程上下文調用同一個(gè)對象的 Threaded::notify() 方法。 為 PHP Threaded 對象提供了強有力的線(xiàn)程間同步控制機制。
應用中會(huì )用在多線(xiàn)程場(chǎng)景中的對象都應該從 Threaded 類(lèi)繼承。
數據存儲: 一般來(lái)說(shuō),任何可以序列化的數據類(lèi)型都可以作為 Threaded 對象的屬性,它可以從持有該對象引用的任何線(xiàn)程上下文讀/寫(xiě)。 并不是所有的數據都采用序列化方式存儲,比如基本類(lèi)型就是以其真實(shí)形態(tài)存儲的。 對于不是 Threaded 派生的對象,例如復雜類(lèi)型、數組以及對象等,都是序列化存儲的,可以從持有 Threaded 對象引用的任何線(xiàn)程上下文中讀取和寫(xiě)入, 區別就在于對于 Threaed 的派生對象,設置它的成員變量的過(guò)程是在獨立線(xiàn)程上下文中執行的。 對于 Threaded 派生對象,在同一時(shí)間,不同的線(xiàn)程上下文都可以從該對象中讀取到同樣的數據。
靜態(tài)成員: 當創(chuàng )建新的線(xiàn)程上下文(Thread 或 Worker 對象)的時(shí)候,靜態(tài)成員會(huì )被拷貝到新的上下文中。出于安全考慮,資源類(lèi)型以及包含內部狀態(tài)的對象類(lèi)型的靜態(tài)成員會(huì )被置空。 實(shí)際上這個(gè)特性實(shí)現了類(lèi)似線(xiàn)程本地存儲的功能。舉例說(shuō)明,假設某個(gè)類(lèi)擁有包含數據庫連接信息以及數據庫連接對象靜態(tài)成員, 那么當新的線(xiàn)程上下文啟動(dòng)的時(shí)候,僅有數據庫連接信息會(huì )被復制到新上下文中,而數據庫連接對象并不會(huì )被復制。 所以,需要在新的上下文中根據復制過(guò)來(lái)的數據庫連接基本信息來(lái)初始化數據庫連接對象,新創(chuàng )建的數據庫連接對象是獨立的, 不影響在原上下文中的數據庫連接對象。
當使用 print_r, var_dump 或者其他函數來(lái)進(jìn)行對象調試的時(shí)候,是沒(méi)有遞歸保護機制的。
注意:
資源類(lèi)型: PHP 中很多使用到 Resource 資源類(lèi)型的擴展或函數并未針對多線(xiàn)程場(chǎng)景進(jìn)行特殊設計,也就是說(shuō),雖然 pthreads 擴展提供了 在多個(gè)線(xiàn)程上下文中共享資源類(lèi)型變量的能力,但是通常來(lái)說(shuō),你應該把它們視為非線(xiàn)程安全的。 所以,如果要在多個(gè)線(xiàn)程上下文中共享資源類(lèi)型的變量,你應該特別謹慎對待。
為了提供一個(gè)穩定的運行環(huán)境,pthreads 擴展在執行過(guò)程中會(huì )有一些必需的額外限制。