摘要:當某種網絡事件發生時,會回調用戶設置的指定回調函數。承擔了底層網絡事件的監聽及各種底層事件處理,當收到請求時,會觸發事件提醒,然后將控制權轉交預先注冊的事件回調函數,來進行后續的處理。請求到來時創建,請求結束后銷毀。
運行流程圖
當啟動一個Swoole應用時,一共會創建2+n+m個進程,2為一個Master進程和一個Manager進程,其中n為Worker進程數,m為TaskWorker進程數。名詞解釋 Master進程
主進程,該進程會創建Manager進程、Reactor線程,UDP收包線程,心跳檢測線程等線程Manger進程
管理進程,該進程的作用是創建、管理所有的Worker進程和TaskWorker進程。
子進程結束運行時,manager進程負責回收此子進程,避免成為僵尸進程。并創建新的子進程
服務器關閉時,manager進程將發送信號給所有子進程,通知子進程關閉服務
服務器reload時,manager進程會逐個關閉/重啟子進程
Worker進程工作進程,所有的業務邏輯代碼均在此進程上運行。當Reactor線程接收到來自客戶端的數據后,會將數據打包通過管道發送給某個Worker進程。
接受由Reactor線程投遞的請求數據包,并執行PHP回調函數處理數據
生成響應數據并發給Reactor線程,由Reactor線程發送給TCP客戶端
可以是異步非阻塞模式,也可以是同步阻塞模式
Worker以多進程的方式運行
TaskWorker進程一種特殊的工作進程,該進程的作用是處理一些耗時較長的任務,以達到釋放Worker進程的目的。
接受由Worker進程通過swoole_server->task/taskwait方法投遞的任務
處理任務,并將結果數據返回(使用swoole_server->finish)給Worker進程
完全是同步阻塞模式
TaskWorker以多進程的方式運行
Reactor線程實際運行Linux中是epoll實例,MacOS中為Kqueue實例,用于accept客戶端連接以及接收客戶端數據。 Swoole的主進程是一個多線程的程序。其中有一組很重要的線程,稱之為Reactor線程。它就是真正處理TCP連接,收發數據的線程。 Swoole的主線程在Accept新的連接后,會將這個連接分配給一個固定的Reactor線程,并由這個線程負責監聽此socket。 在socket可讀時讀取數據,并進行協議解析,將請求投遞到Worker進程。在socket可寫時將數據發送給TCP客戶端。
負責維護客戶端TCP連接、處理網絡IO、處理協議、收發數據
完全是異步非阻塞的模式
全部為C代碼,除Start/Shudown事件回調外,不執行任何PHP代碼
將TCP客戶端發來的數據緩沖、拼接、拆分成完整的一個請求數據包
Reactor以多線程的方式運行
運行機制Swoole是php的擴展,一旦運行后就會接管PHP的控制權,進入事件循環。 當某種IO(網絡IO)事件發生時,Swoole 會回調用戶設置的指定回調函數。 Swoole承擔了底層網絡事件的監聽及各種底層事件處理,當收到請求時,會觸發事件提醒,然后將控制權轉交預先注冊的事件回調函數,來進行后續的處理。 可以理解為Reactor就是nginx,Worker就是php-fpm。Reactor線程異步并行地處理網絡請求,然后再轉發給Worker進程中去處理。Reactor和Worker間通過UnixSocket進行通信。 Swoole提供的TaskWorker是一套更完整的方案,將任務的投遞、隊列、php任務處理進程管理合為一體。通過底層提供的API可以非常簡單地實現異步任務的處理。 另外TaskWorker還可以在任務執行完成后,再返回一個結果反饋到Worker。 Swoole的Reactor、Worker、TaskWorker之間可以緊密的結合起來,提供更高級的使用方式。 一個更通俗的比喻,假設Server就是一個工廠,Master是董事長,Manager是CEO,那Reactor就是銷售經理,接受客戶訂單。而Worker就是工人,當銷售接到訂單后,Worker去工作生產出客戶要的東西。 而TaskWorker可以理解為行政人員,可以幫助Worker干些雜事,讓Worker專心工作。
所謂的回調函數(CallBack) 就好比是張開了夾子的捕鼠器,我們設定當有老鼠踩到捕鼠器的時候,他會關閉夾子然后捉住老鼠,我們放置捕鼠器的時候,捕鼠器并沒有真的抓老鼠。這個設定就是回調,他不立刻執行,會在遇到觸發條件(事件)時執行,在上面的示例當中我們放置了3個捕鼠器(回調函數),我們只需要知道他會在特定老鼠(事件)踩到的時候(發生的時候)去執行我們期望的功能就好。
底層會為Worker進程、TaskWorker進程分配一個唯一的ID
不同的Worker和TaskWorker進程之間可以通過sendMessage接口進行通信
運行周期 程序全局期在swoole_server->start之前就創建好的對象,我們稱之為程序全局生命周期。 這些變量在程序啟動后就會一直存在,直到整個程序結束運行才會銷毀。 有一些服務器程序可能會連續運行數月甚至數年才會關閉/重啟,那么程序全局期的對象在這段時間持續駐留在內存中的。 程序全局對象所占用的內存是Worker進程間共享的,不會額外占用內存。 這部分內存會在寫時分離(COW),在Worker進程內對這些對象進行寫操作時,會自動從共享內存中分離,變為進程全局對象。 程序全局期include/require的代碼,必須在整個程序shutdown時才會釋放,reload無效。進程全局期
swoole擁有進程生命周期控制的機制,一個Worker子進程處理的請求數超過max_request配置后,就會自動銷毀。 Worker進程啟動后創建的對象(onWorkerStart中創建的對象),在這個子進程存活周期之內,是常駐內存的。 onConnect/onReceive/onClose 中都可以去訪問它。 進程全局對象所占用的內存是在當前子進程內存堆的,并非共享內存。對此對象的修改僅在當前Worker進程中有效。 進程期include/require的文件,在reload后就會重新加載。會話期
會話期是在onConnect后創建,或者在第一次onReceive時創建,onClose時銷毀。一個客戶端連接進入后,創建的對象會常駐內存,直到此客戶端離開才會銷毀。 swoole中會話期的對象直接是常駐內存,不需要session_start之類操作。 可以直接訪問對象,并執行對象的方法。請求期
請求期就是指一個完整的請求發來,也就是onReceive收到請求開始處理,直到返回結果發送response。 這個周期所創建的對象,會在請求完成后銷毀。 swoole中請求期對象與普通PHP程序中的對象就是一樣的。 請求到來時創建,請求結束后銷毀。4種PHP回調函數風格 匿名函數
$server->on("Request", function ($req, $resp) use ($a, $b, $c) { echo "hello world"; });
可使用use向匿名函數傳遞參數類靜態方法
class A { static function test($req, $resp) { echo "hello world"; } } $server->on("Request", "A::Test"); $server->on("Request", array("A", "Test"));對象方法
class A { function test($req, $resp) { echo "hello world"; } } $object = new A(); $server->on("Request", array($object, "test"));函數
function my_onRequest($req, $resp) { echo "hello world"; } $server->on("Request", "my_onRequest");編程須知 注意事項
不要在代碼中執行sleep以及其他睡眠函數,這樣會導致整個進程阻塞
在swoole程序中禁止使用exit/die,如果PHP代碼中有exit/die,當前工作的Worker進程、Task進程、User進程、以及swoole_process進程會立即退出。使用exit/die后Worker進程會因為異常退出, 被master進程再次拉起, 最終造成進程不斷退出又不斷啟動和產生大量警報日志。
mt_rand隨機數,在Swoole中如果在父進程內調用了mt_rand,不同的子進程內再調用mt_rand返回的結果會是相同的。所以必須在每個子進程內調用mt_srand重新播種。
while循環的影響,異步程序如果遇到死循環,事件將無法觸發。異步IO程序使用Reactor模型,運行過程中必須在reactor->wait處輪詢。如果遇到死循環,那么程序的控制權就在while中了,reactor無法得到控制權,無法檢測事件,所以IO事件回調函數也將無法觸發。
可通過register_shutdown_function來捕獲致命錯誤,在進程異常退出時做一些清理工作
PHP代碼中如果有異常拋出,必須在回調函數中進行try/catch捕獲異常,否則會導致工作進程退出
不支持set_exception_handler,必須使用try/catch方式處理異常
Worker進程不得共用同一個Redis或MySQL等網絡服務客戶端,Redis/MySQL創建連接的相關代碼可以放到onWorkerStart回調函數中。
異步編程異步程序要求代碼中不得包含任何同步阻塞操作
異步與同步代碼不能混用,一旦應用程序使用了任何同步阻塞的代碼,程序即退化為同步模式
類/函數重復定義新手非常容易犯這個錯誤,由于Swoole是常駐內存的,所以加載類/函數定義的文件后不會釋放。因此引入類/函數的php文件時必須要使用include_once或require_once,否會發生cannot redeclare function/class 的致命錯誤。進程隔離
進程隔離也是很多新手經常遇到的問題。修改了全局變量的值,為什么不生效,原因就是全局變量在不同的進程,內存空間是隔離的,所以無效。所以使用Swoole開發Server程序需要了解進程隔離問題。
不同的進程中PHP變量不是共享,即使是全局變量,在A進程內修改了它的值,在B進程內是無效的
如果需要在不同的Worker進程內共享數據,可以用Redis、MySQL、文件、SwooleTable、APCu、shmget等工具實現
不同進程的文件句柄是隔離的,所以在A進程創建的Socket連接或打開的文件,在B進程內是無效,即使是將它的fd發送到B進程也是不可用的
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/29731.html
摘要:前言都是為了生存有收獲的話請加顆小星星,沒有收獲的話可以反對沒有幫助舉報三連代碼倉庫初始上一什么是面向生產環境的異步網絡通信引擎使開發人員可以編寫高性能的異步并發,服務。 前言:都是為了生存 有收獲的話請加顆小星星,沒有收獲的話可以 反對 沒有幫助 舉報三連 代碼倉庫 初始swoole【上】 一、什么是swoole Swoole:面向生產環境的 PHP 異步網絡通信引擎 使 PHP...
摘要:目錄初識創建服務器上創建服務器下異步任務持續更新中。。。參加工作有一段時間了,偶爾會聽到,對我這種小白粗略看下文檔都會覺得很牛逼。個人理解就是解決這樣應用場景的。 目錄 初識Swoole 創建服務器(上) 創建服務器(下) 異步任務task 持續更新中。。。 參加工作有一段時間了,偶爾會聽到swoole,對我這種PHP小白粗略看下文檔都會覺得很牛逼。由于學習成本比較高,自身對網絡異...
摘要:前言接初識上,這篇主要是異步問題有收獲的話請加顆小星星,沒有收獲的話可以反對沒有幫助舉報三連代碼倉庫初識下異步任務設置異步任務的工作進程數量連接連接歡迎大山驢回調投遞異步任務觸發異步任務服務端回復說處理異步任務新的異步任務 前言:接初識swoole【上】,這篇主要是異步問題 有收獲的話請加顆小星星,沒有收獲的話可以 反對 沒有幫助 舉報三連 代碼倉庫 初識swoole【下】 6、異...
摘要:是一個請求對象,包含了客戶端發來的握手請求信息事件函數中可以調用向客戶端發送數據或者調用關閉連接事件回調是可選的當服務器收到來自客戶端的數據幀時會回調此函數。 前言:了解概念之后就應該練練手啦,不然就是巨嬰 有收獲的話請加顆小星星,沒有收獲的話可以 反對 沒有幫助 舉報三連 代碼倉庫 實戰swoole【聊天室】 在線體驗 準備工作 需要先看初識swoole【上】,了解基本的服務端...
摘要:安裝命令環境下必須關閉選項需要修改關閉在下開發可以使用來方便的開發應用,安裝好后再里的選項里共享代碼所在磁盤。為源碼所在路徑為容器內路徑在里執行編譯安裝擴展是按照標準擴展構建的。 環境依賴 僅支持 Linux、FreeBSD、MacOS 三種操作系統 在Windows平臺,可使用CygWin或WSL(Windows Subsystem for Linux) Linux 內核版本 2....
閱讀 3565·2021-09-24 09:48
閱讀 1087·2021-09-10 10:51
閱讀 3268·2019-08-30 13:03
閱讀 3315·2019-08-30 12:51
閱讀 1388·2019-08-30 11:22
閱讀 1052·2019-08-29 18:38
閱讀 2035·2019-08-29 16:41
閱讀 3183·2019-08-29 15:32