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