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