PHP進程與線程

PHP是單線程,還是多線程的呢服鹅?
PHP是多進程凳兵,還是多線程的呢?
...
解決這些問題企软,首先必須先了解線程和進程庐扫。

備注:進程和線程的都是比較抽象的計算機概念,可參閱《漫畫進程與線程》建立一個初步的認(rèn)知仗哨。

計算機資源

經(jīng)典的馮洛伊曼結(jié)構(gòu)中把計算機系統(tǒng)抽象成“CPU+存儲器+IO”三部分聚蝶,計算機資源無外乎兩種:

馮洛伊曼體系結(jié)構(gòu)
  • 計算單元
    CPU是計算單元,單純從CPU角度來看它是一個黑盒藻治,CPU只對輸入的指令和數(shù)據(jù)進行計算碘勉,然后輸出結(jié)果。CPU不負(fù)責(zé)管理計算那些“指令和數(shù)據(jù)”桩卵。換句話來說验靡,CPU只提供計算能力倍宾,并不負(fù)責(zé)分配計算資源。那么計算資源是由誰來分配的呢胜嗓?計算資源是操作系統(tǒng)來分配的高职,也就是操作系統(tǒng)的調(diào)度模塊,由操作系統(tǒng)按照一定的規(guī)則來分配什么時候由誰來獲得CPU的計算資源辞州,比如分時間片怔锌。
  • 存儲資源
    存儲資源是內(nèi)存、磁盤等存儲設(shè)備的資源变过,操作系統(tǒng)使用虛擬內(nèi)存機制來管理存儲器埃元。從緩存的角度來說,把內(nèi)存作為磁盤的緩存媚狰。進程是面向磁盤的岛杀,為什么這么說呢?進程表示的是一個運行的程序崭孤,程序的代碼段和數(shù)據(jù)段都是存放在磁盤中的类嗤,只是在運行時加載到內(nèi)存中。所以虛擬內(nèi)存面向的是磁盤辨宠,虛擬頁是磁盤的分配遗锣,然后被緩存到物理內(nèi)存的物理頁中。因此嗤形,存儲資源是操作系統(tǒng)由虛擬內(nèi)存機制來管理和分配的精偿,進程則是操作系統(tǒng)分配存儲資源的最小單元。

什么是虛擬內(nèi)存機制派殷,有什么作用呢?

多任務(wù)

現(xiàn)代的操作系統(tǒng)如Windows墓阀、Linux毡惜、UNIX、MacOS等都是支持“多任務(wù)”的操作系統(tǒng)斯撮,那么什么是多任務(wù)呢经伙?

簡單來說,就是操作系統(tǒng)可以同時運行多個任務(wù)∥鸸現(xiàn)在多核CPU已經(jīng)普及帕膜,但在早期單核時代也是可以執(zhí)行多任務(wù)的。由于CPU執(zhí)行代碼都是順序執(zhí)行的溢十,那么單核CPU是如何執(zhí)行多任務(wù)的呢垮刹?

操作系統(tǒng)輪流讓各個讓任務(wù)交替執(zhí)行,表面上看每個任務(wù)都是交替執(zhí)行的张弛,但是由于CPU的執(zhí)行速度很快早抠,在人類的感知中就好像是所有任務(wù)都在同時執(zhí)行一樣。

真正的并行執(zhí)行多任務(wù)只能在多核CPU上實現(xiàn)坛悉,但是由于任務(wù)數(shù)據(jù)遠(yuǎn)遠(yuǎn)超過CPU的核心數(shù)量洋丐。所以,操作系統(tǒng)也會自動把多個任務(wù)輪流調(diào)度到每個核心上去執(zhí)行觉至。

對于操作系統(tǒng)來說,一個任務(wù)就是一個進程。由于每個進程至少要做一件事兒滩字,但有些進程不止同時只做一件事兒。當(dāng)在一個進程中需要同時做多件事情時就需要同時運行多個“子任務(wù)”御吞,我們把進程內(nèi)這些“子任務(wù)”稱為線程麦箍。所以,一個進程至少有一個線程魄藕。

在實際編程中實現(xiàn)多任務(wù)的方式主要有三種:

  • 多進程模式
  • 多線程模式
  • 多進程 + 多線程模式

同時執(zhí)行多個任務(wù)通常各個任務(wù)之間并不是沒有關(guān)系的内列,而是需要相互通信和協(xié)調(diào)。因此背率,多進程和多線程的程序的復(fù)雜度要遠(yuǎn)遠(yuǎn)高于單進程單線程的程序话瞧。

線程是最小的執(zhí)行單元,而進程由至少一個線程組成寝姿。如何調(diào)度進程和線程交排,完全由操作系統(tǒng)決定,程序自己不能決定什么時候執(zhí)行饵筑,執(zhí)行多長時間埃篓。多進程和多線程的程序涉及到同步、數(shù)據(jù)共享等問題根资,編寫起來比單線程更為復(fù)雜架专。

任務(wù)調(diào)度

大部分操作系統(tǒng)如Windows、Linux的任務(wù)調(diào)度是采用時間輪轉(zhuǎn)的搶占式調(diào)度方式玄帕,也就是說部脚,一個任務(wù)執(zhí)行一小段時間后強制暫停去執(zhí)行下一個任務(wù),每個任務(wù)輪流執(zhí)行裤纹。任務(wù)執(zhí)行的一小段時間叫做時間片委刘,任務(wù)正在執(zhí)行的狀態(tài)叫做運行狀態(tài),任務(wù)執(zhí)行一段時間后強制暫停去執(zhí)行下一個任務(wù)鹰椒,被暫停的任務(wù)就處于就緒狀態(tài)并等待下一個屬于它的時間片的到來锡移。這樣往復(fù)循環(huán)每個任務(wù)都得以執(zhí)行,由于CPU的執(zhí)行效率很高漆际,時間片非常短淆珊,在各個任務(wù)之間快速地切換,給人的感覺就是多個任務(wù)在同時運行(并發(fā))奸汇。

操作系統(tǒng)中的任務(wù)調(diào)度

進程Process

什么是進程套蒂?

進程是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)钞支,Multics的設(shè)計者在20世紀(jì)60年代首次使用了“進程”這個技術(shù)詞語,它比“作業(yè)”更加通用一些操刀。

進程是對計算機的一種抽象烁挟,進程表示一個邏輯控制流,也就是一種計算過程骨坑,它造成了一個假象撼嗓,好像這個進程一直是獨占CPU資源的。另外欢唾,進程擁有一個獨立的虛擬內(nèi)存地址空間且警,它也造成了一個假象,好像這個進程一直在獨占存儲資源礁遣。

  • 進程是正在執(zhí)行的程序
  • 進程是正在計算機上執(zhí)行的程序的實例
  • 進程是能分配到CPU并由CPU執(zhí)行的實體
  • 進程由單一順序的執(zhí)行線程斑芜、一個當(dāng)前狀態(tài)、一組相關(guān)的系統(tǒng)資源三者所描述的活動單元祟霍。

進程包含指令集和系統(tǒng)資源集

  • 指令集:指的是程序代碼
  • 系統(tǒng)資源集:是指I/O杏头、CPU、內(nèi)存等沸呐。

簡單來說醇王,進程是具有一定獨立功能的程序,在關(guān)于某個數(shù)據(jù)集合上的一次運行活動崭添。換言之寓娩,進程是一個程序在一個數(shù)據(jù)集上的一次動態(tài)執(zhí)行過程,是系統(tǒng)進行資源分配和調(diào)度的一個獨立單位呼渣。

進程一般由程序棘伴、數(shù)據(jù)集、進程控制塊三部分組成:

  • 程序:編寫的程序是用來描述進程要完成那些功能以及如何完成
  • 數(shù)據(jù)集:是程序在執(zhí)行過程中所需要使用的資源
  • 進程控制塊:是用來記錄進程的外部特征屁置,描述進程的執(zhí)行變化過程焊夸,系統(tǒng)可以利用它來控制和管理進程,是系統(tǒng)感知進程存在的唯一標(biāo)志缰犁。

也可以把進程當(dāng)作由一組元素組成的實體淳地,進程的兩個基本元素是:

  • 程序代碼:可能被執(zhí)行相同程序的其它進程共享
  • 代碼相關(guān)聯(lián)的數(shù)據(jù)集

假如CPU開始執(zhí)行這個程序代碼怖糊,把這個執(zhí)行實體稱為進程帅容。在進程執(zhí)行時,任意給定時間伍伤,進程都可以唯一的被表征為以下元素:

進程元素
  • 進程描述符
    進程的唯一標(biāo)識符并徘,用來和其它進程區(qū)分。在Linux中叫做進程ID(pid)扰魂,它在系統(tǒng)調(diào)用fork創(chuàng)建子進程時生成麦乞,注意若使用getpid返回的其實并不是進程ID蕴茴,而是線程組號tgid
  • 進程狀態(tài)
    進程的狀態(tài)包括就緒姐直、掛起倦淀、運行...
  • 優(yōu)先級
    與進程之間執(zhí)行調(diào)度相關(guān),是相對于其它進程而言的声畏。
  • 程序計數(shù)器
    程序中即將被執(zhí)行的下一條指令的地址撞叽,是內(nèi)核或用戶內(nèi)存空間中的內(nèi)存地址。
  • 內(nèi)存指針
    包含程序代碼和進程相關(guān)數(shù)據(jù)的指針插龄,以及與其它進程共享內(nèi)存塊的指針愿棋。
  • 上下文數(shù)據(jù)
    進程執(zhí)行時CPU處理器上寄存器中的數(shù)據(jù)。
  • IO狀態(tài)
    包含顯式的I/O請求均牢、分配給進程的I/O設(shè)備等糠雨。
  • 記賬信息
    可能包含CPU處理時間總和、使用的時鐘總和徘跪、時間限制等甘邀。

進程控制塊PCB

進程控制塊

進程的構(gòu)成元素會被存放在一個叫做“進程控制塊”(PCB,Processing Control Block)的數(shù)據(jù)結(jié)構(gòu)中真椿,進程控制塊是操作系統(tǒng)能夠支持多進程和多任務(wù)的結(jié)構(gòu)鹃答。

當(dāng)操作系統(tǒng)執(zhí)行進程切換時,會執(zhí)行兩步操作:

  • 中斷:中斷當(dāng)前CPU處理中的進程
    當(dāng)進程中斷時突硝,操作系統(tǒng)會把程序計數(shù)器测摔、CPU處理器寄存器(對應(yīng)進程控制塊中的上下文數(shù)據(jù))保存到進程控制塊中的相應(yīng)位置,進程狀態(tài)也會發(fā)生變化解恰,可能進入阻塞狀態(tài)锋八,也可能進入就緒狀態(tài)。
  • 執(zhí)行:執(zhí)行下一個進程
    當(dāng)執(zhí)行下一個進程時护盈,操作系統(tǒng)會按規(guī)則將下一個進程設(shè)置為運行狀態(tài)挟纱,并加載即將要執(zhí)行進程的程序上下文數(shù)據(jù)和程序計數(shù)器等。

不管是中斷還是執(zhí)行腐宋,進程控制塊中的程序計數(shù)器紊服、上下文數(shù)據(jù)、進程狀態(tài)都會發(fā)生變化胸竞。

線程Thread

為什么會存在線程這樣的概念欺嗤?它解決了什么樣的問題呢?

在早期的操作系統(tǒng)中并沒有線程的概念卫枝,進程是擁有資源和獨立運行的最小單位煎饼,也就是程序執(zhí)行的最小單位。任務(wù)調(diào)度采用時間片輪轉(zhuǎn)的搶占式調(diào)度方式校赤,由于進程是任務(wù)調(diào)度的最小單位吆玖,每個進程由各自獨立的一塊內(nèi)存筒溃,使得各個進程之間內(nèi)存地址相互隔離。

早期沒有線程時候的進程

隨著計算機的發(fā)展沾乘,對CPU的要求越來越高怜奖,進程之間的切換開銷越來越大,對多個任務(wù)之間上下問切換的效率要求越來越高翅阵,已經(jīng)無法滿足越來越復(fù)雜的程序的要求了烦周。于是就出現(xiàn)了線程,線程是程序執(zhí)行中一個單一的順序控制流程怎顾,是程序執(zhí)行流的最小單元读慎,是處理器調(diào)度和分派的基本單位。

線程

一個進程可以由一個或多個線程槐雾,各個線程之間共享程序的內(nèi)存空間夭委,也就是所在進程的內(nèi)存空間。一個標(biāo)準(zhǔn)的線程由線程ID募强、當(dāng)前指令指針(PC)株灸、寄存器和堆棧組成。而進程由內(nèi)存空間和多個線程組成擎值。

理論上來說慌烧,在Linux內(nèi)核中是沒有線程這個概念的,只有內(nèi)核調(diào)度實體(Kernal Scheduling Entry鸠儿,KSE)這個概念屹蚊。Linux的線程本質(zhì)上是一種輕量級的進程(Light Weight Process, LWP)进每,是通過clone克隆系統(tǒng)調(diào)用來創(chuàng)建的汹粤。由于進程是一種KSE,線程也是一種KSE田晚。所以線程是操作系統(tǒng)調(diào)度的最小單元嘱兼。

進程是程序執(zhí)行時的一個實例,是程序執(zhí)行到某種程度的數(shù)據(jù)結(jié)構(gòu)的匯集贤徒。從內(nèi)核的角度來看芹壕,進程的就是分配系統(tǒng)資源的基本單位。

線程是進程的一個執(zhí)行流接奈,是CPU調(diào)度和分派的基本單位踢涌。線程是比進程更小的能獨立運行的基本單位。簡單來說鲫趁,進程是資源分配的最小單位斯嚎,線程是程序執(zhí)行的最小單位利虫。

一個進程會由多個線程組成挨厚,線程與同屬一個進程的其它線程共享進程所擁有的全部資源堡僻。

進程與線程

進程有兩個特性部分:資源所有權(quán)和調(diào)度執(zhí)行

  • 資源所有權(quán):是指進程包含了進程運行所需的內(nèi)存空間、I/O等資源疫剃。
  • 調(diào)度執(zhí)行:是指進程執(zhí)行過程中間的執(zhí)行路徑钉疫,或者說程序的指令執(zhí)行流。

進程的這兩個特性部分是可以分開的巢价,分開后擁有資源所有權(quán)的通常稱為進程牲阁,擁有執(zhí)行代碼的可分派部分的被稱之為線程或輕量級進程。

線程Thread有“執(zhí)行的線索”的意思在其中壤躲,而進程Process在多線程環(huán)境中被定義為資源所有者城菊,還會存儲進程的進程控制塊PCB

線程的結(jié)構(gòu)

線程的結(jié)構(gòu)與進程不同碉克,每個線程包含四部分:

  • 線程狀態(tài):線程的當(dāng)前狀態(tài)
  • 一個執(zhí)行棧
  • 私有的數(shù)據(jù)區(qū):用于存放每個線程局部變量的靜態(tài)存儲空間
  • 寄存器集:用于存儲CPU處理器的一些狀態(tài)

每個進程都有一個進程控制塊和用戶地址空間凌唬,每個線程都有一個獨立的棧和獨立的控制塊,以及一個獨立執(zhí)行上下文漏麦。

進程模型

線程的執(zhí)行過程

線程的執(zhí)行過程與進程不同客税,每個獨立的線程有一個程序運行的入口、順序執(zhí)行序列和程序的出口撕贞。線程不能夠獨立執(zhí)行更耻,必須依存于進程之中,由于進程提供多個線程執(zhí)行控制捏膨。從邏輯上看秧均,多線程的意義在于一個進程中,有多個執(zhí)行部分可以同時執(zhí)行号涯。此時熬北,進程本身不是基本運行單位,而實線程的容器诚隙。

線程于進程對比而言讶隐,優(yōu)勢在于快,不管是線程的創(chuàng)建還是終止久又,不管是線程間的切換還是線程間共享數(shù)據(jù)或通信巫延,它的速度于進程相比都有較大的優(yōu)勢。

單線程與多線程

單線程與多線程

進程與線程的關(guān)系

  • 一個線程只能屬于一個進程地消,而一個進程可以擁有多個線程炉峰,但至少有一個線程(主線程)。
    多線程處理就是允許一個進程中在同一時刻執(zhí)行多個任務(wù)
  • 線程是一種輕量級的進程脉执,與進程相比疼阔,線程給操作系統(tǒng)帶來的維護和管理的負(fù)擔(dān)要小,以就是說線程的開銷代價更小。
  • 系統(tǒng)資源分配給進程婆廊,同一進程中的所有線程共享這個進程的所有資源迅细。
  • CPU會分給線程,換句話說淘邻,真正在CPU上運行的是線程茵典。
  • 線程沒有地址空間,線程包含在進程的地址空間中宾舅。線程上下文只包含一個堆棧统阿、一個寄存器、一個優(yōu)先權(quán)筹我。線程文本包含在它的進程文本段中扶平,進程擁有的所有資源都屬于線程。所有的線程共享進程的內(nèi)存和資源蔬蕊。同一進程中的多個線程共享代碼段(代碼和常量)蜻直、數(shù)據(jù)段(全局變量和靜態(tài)變量)、擴展段(堆存儲)袁串。但是每個線程擁有自己的堆段(運行時段概而,用來存放所有局部變量和臨時變量)、寄存器內(nèi)容囱修。
  • 父子進程使用進程間通信機制赎瑰,同一進程的線程通過讀取和寫入數(shù)據(jù)到進程變量來進行通信。

并發(fā)與并行

  • 并發(fā)
    并發(fā)又稱為共行破镰,是指能夠處理多個同時性活動的能力餐曼。并發(fā)事件之間不一定要同一時刻發(fā)生。現(xiàn)代計算機系統(tǒng)可以在同一段時間內(nèi)以進程的形式鲜漩,將多個程序加載到存儲器中源譬,并借由CPU處理的時分復(fù)用,制造出在一個CPU處理器上展現(xiàn)同時運行的錯覺孕似。

  • 并行
    并行是指同時發(fā)生的兩個并發(fā)事件踩娘,并行具有并發(fā)的含義,并發(fā)則不一定會并行喉祭。

簡單來說养渴,并發(fā)和并行的區(qū)別在于一個CPU處理器同時處理多個任務(wù)和多個CPU處理器或者是多核處理器同時處理多個不同的任務(wù),并發(fā)是邏輯上同時發(fā)生泛烙,而并行則是物理上的同時發(fā)生理卑。

高并發(fā)

可參見《高并發(fā)原理》,后續(xù)待補蔽氨。

多進程與多線程的關(guān)系

多進程與多線程

使用多進程的優(yōu)勢

  • 子進程結(jié)束后藐唠,系統(tǒng)內(nèi)核會負(fù)責(zé)回收資源帆疟。
  • 子進程異常退出時不會導(dǎo)致整個進程退出,父進程還有機會重建流程宇立。
  • 一個常駐主進程踪宠,只負(fù)責(zé)任務(wù)分發(fā),邏輯會更加清晰泄伪。
  • 使用多進程更加穩(wěn)定,另外利用進程間通信IPC也可以實現(xiàn)數(shù)據(jù)共享匿级。
  • 使用多進程共享內(nèi)存和線程間讀寫變量是一樣的蟋滴,同樣需要加鎖,會有同步痘绎、死鎖問題津函。
  • 使用多進程消息隊列,可以采用多個子進程搶奪隊列模式孤页,性能很好尔苦。

使用多線程得優(yōu)勢

  • 線程是在同一個進程內(nèi)的,可以共享內(nèi)存變量實現(xiàn)線程間通信行施。
  • 線程比進程更輕量級允坚,開大量進程比線程消耗更多系統(tǒng)資源。

使用多線程存在的問題

  • 線程讀寫變量存在同步問題需要加鎖
  • 鎖得粒度過大時會存在性能問題蛾号,可能會導(dǎo)致只有一個線程在運行稠项,其它線程都在等待鎖。
  • 同時使用多個鎖鲜结,邏輯會很復(fù)雜展运,一旦某個鎖沒有被正確釋放,可能會發(fā)生線程死鎖精刷。
  • 某個線程發(fā)生指明錯誤會導(dǎo)致整個進程崩潰

并發(fā)模型

C10K(Client 10000)問題 - 如何單服同時服務(wù)1w個客戶端拗胜?

由于早期服務(wù)器是基于進程/線程模型,每新來一個連接就分配一個進程/線程去處理這個連接怒允,而進程/線程在操作系統(tǒng)中會占用一定的資源的埂软。由于硬件的限制,進程/線程的創(chuàng)建是有瓶頸的纫事。另外仰美,進程/線程的上下文切換也是有成本的,每次調(diào)度器調(diào)度線程儿礼,操作系統(tǒng)都要把線程的各種必要信息如程序計數(shù)器咖杂、堆棧、寄存器蚊夫、狀態(tài)等保存起來诉字。

由于CPU的運算速度遠(yuǎn)快于I/O操作,互聯(lián)網(wǎng)應(yīng)用如Web都是I/O密集型而非計算密集型的。I/O密集型是指計算機CPU大量的時間耗費在等待數(shù)據(jù)的輸入和輸出上壤圃,而不是計算上陵霉。當(dāng)CPU大部分時間都在等待I/O的時候,大部分計算資源是被浪費掉了的伍绳。顯然踊挠,簡單粗暴地開一個進程/線程去處理一個連接時不夠的,為了達(dá)到高并發(fā)冲杀,需要重點思考的是I/O策略(模型)效床,在同樣的硬件條件下不同的設(shè)計會產(chǎn)生很大的差異。

PHP并發(fā)模型

PHP并發(fā)模型可分為多進程模型和多線程模型权谁,那么PHP使用的哪一種呢剩檀?答案是都支持,也就是說PHP支持多線程的模型旺芽,在多線程情況下沪猴,通常要解決的問題是資源共享和隔離,而PHP自身就是線程安全的采章。

那么到底是哪一種呢运嗜?具體來說就需要看PHP所使用的是那個SAPI,例如在Apache中就可能使用多線程模型也可能使用多進程模型悯舟,在PHP-FPM中使用的就是多進程模型洗出。

目前比較推薦的方式是使用PHP-FPM的模型,因為這個模型對PHP來說有諸多優(yōu)勢:

  • 內(nèi)存釋放簡單
    使用多進程模型時图谷,進程可以很容易通過退出的方式來釋放內(nèi)存翩活,由于PHP有很多擴展,稍有不慎就可能導(dǎo)致內(nèi)存泄漏便贵,PHP-FPM通過進程退出的方式菠镇,簡單粗暴的解決了問題。
  • 容災(zāi)能力強
    由于PHP擴展或PHP自身可能會出現(xiàn)錯誤承璃,如果是單進程多線程模型利耍,那么整個PHP就掛掉了,這直接就影響到服務(wù)盔粹。多進程的話隘梨,即使某個進程死掉了也不會影響整個服務(wù)。

多進程與多線程各具優(yōu)勢舷嗡,例如HHVM選擇的就是多線程模型轴猎,多線程模型最大的好處是數(shù)據(jù)共享和通信方便,因為在同一個進程空間內(nèi)进萄,可以直接使用指針捻脖。在PHP的opcode cache工具中apc和opcache等使用的是共享內(nèi)存來共享opcode锐峭,而在HHVM中則不需要走共享內(nèi)存。共享內(nèi)存有個問題是存儲復(fù)雜的數(shù)據(jù)結(jié)構(gòu)不方便可婶,因為指針的問題沿癞,多線程情況下C/C++中的數(shù)據(jù)結(jié)構(gòu)是可以共享的。這對效率提升也是有幫助的矛渴。

多進程和多項還有一個明顯的模型區(qū)別是在處理請求時的邏輯上

  • 多進程
    由于跨進程時不容易傳遞fd客戶端唯一連接標(biāo)識的椎扬,在多進程中,通常采用的是在父進程中listen()具温,然后給子進程accept()的方式來實現(xiàn)負(fù)載均衡蚕涤,這樣的模型下可能會有驚群的問題。
  • 多線程
    多線程模型下可以采用一個獨立線程接收請求然后派發(fā)到各個worker工作線程中去桂躏。

多線程的PHP

PHP從代碼級別來講是不支持多線程操作的钻趋,不能像Java川陆、C#等語言一樣編寫多線程代碼剂习。多線程只是代碼運行時在同一時刻同時執(zhí)行多個線程任務(wù),來提高服務(wù)器CPU的利用率较沪。PHP是可以以多進程方式執(zhí)行鳞绕,例如PHP的進程管理工具PHP-FPM的進程管理機制就是采用了多進程單線程的方式,有效提高了并發(fā)訪問的響應(yīng)效率尸曼。

PHP從設(shè)計之初到流行起來都沒有出現(xiàn)明顯需要多線程才能解決問題的需求们何,某些需要多線程的地方也有相應(yīng)的解決方案和替代方案。而且多線程并不總是比單線程具有更多優(yōu)勢控轿,另外多線程可能會引入其它問題冤竹,例如多個線程同時調(diào)用一個類中的同一個方法時,可能出現(xiàn)死鎖的情況茬射。

簡單來說鹦蠕,對于一個客戶端的一個頁面請求處理的PHP是單線程的,這樣做的好處是可以自上而下的編寫和理解代碼中的業(yè)務(wù)邏輯在抛。但在PHP是可以同時開啟多個線程來處理多個客戶端請求的同一個PHP腳本钟病,所以PHP也可以看成是多線程的。

雖然每個PHP腳本的執(zhí)行是單線程的刚梭,但對于Web服務(wù)器組件如Apache/Nginx/PHP-FPM是多線程的肠阱,因為客戶端每次對某個PHP腳本的發(fā)起請求時,Web服務(wù)器都會創(chuàng)建一個新的進程/線程朴读,用來執(zhí)行對應(yīng)的PHP腳本屹徘。也就是說,對于一個客戶端請求來說衅金,PHP是單線程的缘回,但多個請求間是并發(fā)的吆视。

簡單來說,PHP本身是不支持多線程酥宴,但是Web服務(wù)器是支持多線程的啦吧,利用Web服務(wù)器本身的多線程來處理,從Web服務(wù)器多次調(diào)用實現(xiàn)多線程的程序拙寡。也就是說授滓,可以多人同時訪問,這也就是在PHP中實現(xiàn)多線程的基礎(chǔ)肆糕。

PHP線程安全

如何選擇PHP的版本般堆,TS or NTS?

由于Linux/UNIX系統(tǒng)采用多進程的工作方式诚啃,而Windows系統(tǒng)采用多線程的工作方式淮摔。如果在Windows的IIS下以CGI方式運行PHP會非常慢,因為CGI模式是建立在多進程的基礎(chǔ)之上的始赎,而非多線程和橙。所以,在Windows IIS中會把PHP配置成以ISAPI的方式來運行造垛,ISAPI是多線程方式魔招。但存在要給問題,很多PHP擴展時以Linux/UNIX的多進程思想開發(fā)的五辽,這些擴展在ISAPI方式運行時出錯并搞垮IIS办斑。因此,在IIS下CGI模式才是PHP運行的最安全方式杆逗,但CGI對于每個HTTP請求都需要重新記載和卸載整個PHP環(huán)境乡翅,其消耗是巨大的。

為了兼顧IIS下PHP的效率和安全罪郊,Microsoft提出了FastCGI的解決方案蠕蚜,F(xiàn)astCGI可以讓PHP的進程重復(fù)利用,而不是為每個新請求就重開一個進程排龄。同時FastCGI也可以運行多個進程同時執(zhí)行波势,這樣即解決了CGI進程模式消耗太大的問題,又利用上了CGI進程模式不存在線程安全問題的優(yōu)點橄维。

因此尺铣,如果PHP使用ISAPI的方式運行就必修使用線程安全(Thread Safe, TS)的版本争舞,如果使用FastCGI模式就沒有必要使用線程安全檢查凛忿,可采用非線程安全(None Thread Safe, NTS)版本以提高效率竞川。

ZTS是什么店溢?

PHP的SAPI多數(shù)是單線程環(huán)境叁熔,比如CGI、CLI床牧、FPM荣回,每個進程只啟動一個主線程,這種模式下是不存在線程安全問題的戈咳。但也又多線程的環(huán)境心软,如Apache,在這種情況下就需要考慮線程安全問題著蛙。因為PHP中又很多全局變量删铃,如EG、CG踏堡。如果多個線程共享同一個變量將會發(fā)生沖突猎唁,所以PHP為多線程的應(yīng)用模型提供了一個安全機制 - Zend線程安全(Zend Thread Safe,ZTS)顷蟆。

PHP專門為解決線程安全問題抽象出一個線程安全資源管理器(Thread Safe Resource Manager, TSRM)诫隅,實現(xiàn)原理:既然共用資源這么困難那么就不共用,各線程不再共享同一份全局變量慕的,而是各自復(fù)制一份阎肝,使用數(shù)據(jù)時各個線程各自取自己的副本挤渔,互不干擾肮街。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市判导,隨后出現(xiàn)的幾起案子嫉父,更是在濱河造成了極大的恐慌,老刑警劉巖眼刃,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绕辖,死亡現(xiàn)場離奇詭異,居然都是意外死亡擂红,警方通過查閱死者的電腦和手機仪际,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昵骤,“玉大人树碱,你說我怎么就攤上這事”淝兀” “怎么了成榜?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蹦玫。 經(jīng)常有香客問我赎婚,道長刘绣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任挣输,我火速辦了婚禮纬凤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘撩嚼。我一直安慰自己移斩,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布绢馍。 她就那樣靜靜地躺著向瓷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舰涌。 梳的紋絲不亂的頭發(fā)上猖任,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音瓷耙,去河邊找鬼朱躺。 笑死,一個胖子當(dāng)著我的面吹牛搁痛,可吹牛的內(nèi)容都是我干的长搀。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼鸡典,長吁一口氣:“原來是場噩夢啊……” “哼源请!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起彻况,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤谁尸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后纽甘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體良蛮,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年悍赢,在試婚紗的時候發(fā)現(xiàn)自己被綠了决瞳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡左权,死狀恐怖皮胡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情涮总,我是刑警寧澤胸囱,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站瀑梗,受9級特大地震影響烹笔,放射性物質(zhì)發(fā)生泄漏裳扯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一谤职、第九天 我趴在偏房一處隱蔽的房頂上張望饰豺。 院中可真熱鬧,春花似錦允蜈、人聲如沸冤吨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漩蟆。三九已至,卻和暖如春妓蛮,著一層夾襖步出監(jiān)牢的瞬間怠李,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工蛤克, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捺癞,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓构挤,卻偏偏與公主長得像髓介,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子筋现,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 1. 簡介 用戶打開瀏覽器夫否,其實就是打開了瀏覽器應(yīng)用程序彻犁。那么什么是程序呢叫胁?我們常說瀏覽器是多線程的凰慈,JS 是單線...
    love丁酥酥閱讀 3,509評論 0 6
  • 一. 操作系統(tǒng)概念 操作系統(tǒng)位于底層硬件與應(yīng)用軟件之間的一層.工作方式: 向下管理硬件,向上提供接口.操作系統(tǒng)進行...
    月亮是我踢彎得閱讀 5,959評論 3 28
  • 除了充分利用計算機處理器的能力外,一個服務(wù)端同時對多個客戶端提供服務(wù)則是另一個更具體的并發(fā)應(yīng)用場景驼鹅。衡量一個服務(wù)性...
    胡二囧閱讀 1,324評論 0 12
  • 必備的理論基礎(chǔ) 1.操作系統(tǒng)作用: 隱藏丑陋復(fù)雜的硬件接口微谓,提供良好的抽象接口。 管理調(diào)度進程输钩,并將多個進程對硬件...
    drfung閱讀 3,530評論 0 5
  • 感賞兒子:昨晚睡的很晚豺型,今天早上不想去起床,但后來聽從了媽媽的建議买乃,又上學(xué)去了姻氨。 投射自己:合理安排生活,今天雖是...
    牛津大學(xué)閱讀 230評論 0 0