於swoole 4.0全新的PHP編程模式node
上面是一段PHP代碼,其中2個函數的執行時間都是1秒,整段代碼執行完成須要2秒。要想將這種串行執行方式轉換爲並行執行,在PHP中能夠經過建立多進程來執行每一個函數,單個進程執行單個函數,這樣在1秒鐘能就能執行完上面的代碼。雖然在Java中多線程應用很廣泛,可是很惋惜PHP並不支持多線程。web
除開多線程和多進程,還有一種方式也能實現並行編程,那就是協程(Coroutine),這也是GO語言的重要特性。協程的併發量相對多線程和多進程要高出不少,同一個進程內能夠建立幾十萬甚至上百萬個協程,且只佔用少許的內存空間。線程和進程由操做系統調度,是很是昂貴的系統資源,建立過多的話,在上下文保存和進行切換的開銷上會很大。spring
這裏將前面的代碼以協程的形式進行了重寫,執行的時候會建立兩個協程,執行時間爲1秒。雖然執行效果和多進程或多線程同樣,但實現原理有所不一樣。協程中這兩個函數的執行基於一種自動讓出的機制,一旦執行函數遇到IO操做,就會自動讓出當前執行棧交由下一個函數執行,在IO完成以後再恢復協程棧。編程
PHP因爲自身的自然缺陷沒法支持多線程,因此咱們繞開了它直接在swoft 4.0中實現了協程。但因爲針對CPU密集操做只能利用到一個核,因此在使用協程的時候仍是會利用多進程的方式來複用CPU的多核操做。數組
協程最大的好處在於可以提供極大的併發,由於它僅佔用內存,不存在進程/線程切換開銷,單個進程就可開啓50w個協程。服務器
咱們在swoft 1.0的時候採用的技術方案和node.js的異步回調同樣,在2.0的時候開始嘗試實現協程,可是存在一些缺陷——協程不能用在全部的函數上,只能用在一些已經預約好的函數上。這是因爲PHP有一些動態的特性,好比將URL映射到一個類方法上,這種場景下執行2.0的協程程序就會崩潰。4.0的時候咱們對此作了一些優化,基於微信開源的庫從新實現了協程方案,這時的協程就達到了在Go語言中的效果。微信
上面展現的就是PHP中使用協程的三種方式。左上的代碼經過循環的方式建立了10個協程,下面這段則是在協程中執行讀文件的操做,且內部還嵌套了兩個協程,它們之間是相互依賴的關係。右邊的代碼直接建立了3個協程,每一個協程的執行邏輯都不同。websocket
有了協程以後,就會涉及到如何管理協程或數據通訊的問題。在Java多線程中,線程之間的通訊可能會使用鎖或者數據結構的方式解決,在協程編程中通常使用的chan的方式管理。swoole
協程是一個用戶態的線程,同一時間執行的協程只有一個。這一點和多線程不一樣,建立出來的多個線程都會並行執行。數據結構
左邊這段代碼是協程編程,它會讀取一個全局的數組,當協程1讀取數組的時候,協程2其實沒有運行,直到協程1遇到IO操做釋放了控制權,協程2纔會恢復再去讀全局變量,這樣就徹底不用加鎖了。
右邊是線程編程,能夠看到若是程序要讀取全局臨界資源就必定要加鎖,要不斷的lock、unlock。
Chan有點相似隊列,不過它自帶了協程調度能力。
多線程讀取隊列時,會有生產者和消費者。在隊列內存佔用過多沒法再寫入的狀況下,生產者仍是會持續寫入,通常的解決方案是進行盲等,好比讓生產者sleep一段時間而後再去寫入。在隊列無數據可返回的狀況下,一種方案是讓消費者盲等,CPU死循環去等待,不過這樣會佔滿CPU。通常的方案是在發現無數據返回的時候sleep一段時間,以後再嘗試讀取。
協程編程中能夠經過chan來完成協程調度。當生產者發現容量不足的時候會展現掛起當前協程,直到有消費者拿走一些數據以後纔會喚醒這個協程。消費者的讀取機制也是同樣的,無可用數據時就掛起,一旦生產者push數據後再喚醒。
因爲PHP的動態語言特性,因此能夠向chan中push任意的PHP變量,不管是對象仍是數組。Chan的底層基於引用計數管理,徹底沒有內存拷貝,除了標量類型是直接複製以外,包括數組、對象這些複雜的數據結構都是用的引用計數管理。像Go語言同樣,咱們也提供了chan::select用來對多個chan進行讀寫判讀。
協程框架swoft的介紹
Swoft是基於協程實現的web開發框架。它借鑑了spring Cloud作了徹底組件化的實現,裏面不少功能都是一個小的組件,固然也能夠用自定義的組件替換內置的組件。該框架也提供了依賴注入、容器、鏈接池、AOP,除了應用在web領域以外,還可以用在微服務上。
上面兩行命令分別是用來建立swoft工程和引入相關組件。
目前swoft支持3種服務器,swoft-http-srever 、swoft-websocket-server swoft-rpc-server。 第一個用來作主流的web應用程序,第二個是長鏈接通訊服務,最後是微服務領域的RPC服務。
經過命令行腳本可以直接啓用以上3種服務,這裏也提供了一些經常使用的腳本工具。
Swoft參考Java的Spring框架,用了不少註解編程的方式。對於Web開發中的URL映射,能夠直接經過註解的方式寫Route。可以自動將URL映射到當前Controller方法中,URL中的參數也會自動帶入類方法中。
基於swoft協程框架進行PHP微服務治理
Swoft自帶了一些微服務經常使用的組件,包括服務註冊、熔斷、降級、負載均衡、接口多版本等。
Swoft的服務註冊與發現是基於Google開源的consul,要使用consul須要添加一些配置,定義服務提供方和接入方的key。而後在前面提到的命令行腳本調用RPC start就會自動將咱們的服務器節點註冊到consul服務器中。
Swoft的接口聲明也是基於註解的方式,如上圖所示經過註解定義了service指向的服務以及調用的接口,調用的時候會映射到對應的方法。
swoft的熔斷機制中失敗超過必定次數,服務就關閉,成功的話,服務從新鏈接。
這段代碼是關於熔斷器的調用,首先肯定熔斷器的名詞,正常狀況下調用handler,失敗的話就調用fallback進行一些處理。
這裏關於微服務的介紹可能比較簡要,實際上是由於作服務治理更多的仍是要用成熟的框架。PHP方面咱們推薦使用Tars,這是騰訊開源的微服務治理框架,基於WUP結構定義文件,能夠自動生成接口骨架代碼,有着完整的服務治理方案,自帶發佈、運維、監控、彈性伸縮體系。