Swoole的進(jìn)程模型

前文再續(xù),就書(shū)接上一回,隨著與Server、TCP、Protocol的邂逅,Swoole終于迎來(lái)了自己的故事,今天,我們來(lái)聊聊Swoole的進(jìn)程模型。


前邊幾篇東西雖然標(biāo)題是Swoole,其主要講的是操作系統(tǒng)、計(jì)算機(jī)網(wǎng)絡(luò)方面的知識(shí),包括一點(diǎn)點(diǎn)筆者自己的私貨,今天終于放假了,咱可以討論一下公的了=。=


并發(fā)之始


之前我們已經(jīng)初步討論的一個(gè)WebServer是怎樣工作的,但之前的例子中,我們看到的服務(wù)都是一個(gè)客戶端與一個(gè)服務(wù)端一問(wèn)一答的場(chǎng)景,但事實(shí)上,絕大部分時(shí)候我們預(yù)期的服務(wù)并不是只向一個(gè)客戶端提供服務(wù),所以,作為一個(gè)成熟的Server,并發(fā)\并行問(wèn)題是必須解決的。


其實(shí),“并發(fā)”和“并行”兩個(gè)概念在計(jì)算機(jī)中是相關(guān)但不同的,有興趣的童鞋可以自己搜索一下,筆者今天僅討論并發(fā)咯。


而軟件開(kāi)發(fā)中,最常見(jiàn)的并發(fā)問(wèn)題解決方案,莫過(guò)于多線程/多進(jìn)程兩種模式了。


微軟的體系中,除了線程,還有“纖程”;而最近非常火爆的“協(xié)程”,則又是另一個(gè)解決方案了。


在《計(jì)算機(jī)組成原理》中我們都學(xué)過(guò),并發(fā)中最迫切需要解決的問(wèn)題之一,就是數(shù)據(jù)的可靠性問(wèn)題,而不同的并發(fā)模型,其并發(fā)數(shù)據(jù)可靠性的機(jī)制往往各有特點(diǎn),因此,在使用Swoole Server\Client的過(guò)程中,其并發(fā)解決方案的模型是必須要了解的,否則使用上很容易出現(xiàn)不符合預(yù)期的結(jié)果。


## 簡(jiǎn)單說(shuō),就是防止臟讀臟寫(xiě)


Swoole目前總共有三種運(yùn)行模式,其中Base模式基本沒(méi)有生產(chǎn)應(yīng)用價(jià)值;協(xié)程模式暫時(shí)還處于預(yù)覽階段;因此,筆者在此想和大家討論的,就是Swoole的多進(jìn)程模式,也是官方目前最推薦用于生產(chǎn)環(huán)境的模式。


事實(shí)上,Swoole曾經(jīng)還有多線程模式,但由于Zend在多線程模式本身的缺陷,在1.6版本后,多線程模式已經(jīng)被關(guān)閉。


進(jìn)程模型


首先,我們還是來(lái)簡(jiǎn)單回顧一下Swoole Server的構(gòu)造函數(shù),之前我們已經(jīng)解決了Host、Port、Protocol的問(wèn)題,這期我們來(lái)看最后一個(gè)參數(shù)的:




$server=new\swoole_server("127.0.0.1",8088,SWOOLE_PROCESS,SWOOLE_SOCK_TCP);


第三個(gè)參數(shù)mode中我們填入的PROCESS,即表示當(dāng)前Server是運(yùn)行于多進(jìn)程模式的。


其他mode的可選參數(shù)可以參考手冊(cè)


然后,我們簡(jiǎn)單實(shí)現(xiàn)一個(gè)沒(méi)有任何內(nèi)容的Server:




$server=new\swoole_server("127.0.0.1",8088,SWOOLE_PROCESS,SWOOLE_SOCK_TCP);


$server->on('connect',function($serv,$fd){ });


$server->on('receive',function($serv,$fd,$from_id,$data){ });


$server->on('close',function($serv,$fd){ });


$server->start();


在啟動(dòng)服務(wù)之后,我們繼續(xù)在Shell中輸入以下命令:


>php swoole_server_demo.php


>pstree -ap|grep swoole_server_demo


|-php,2829 swoole_server_demo.php


||-php,2831 swoole_server_demo.php


||`-php,2836 swoole_server_demo.php


pstree命令可以查看進(jìn)程的樹(shù)模型


從系統(tǒng)的輸出中,我們可以很容看出server其實(shí)有3個(gè)進(jìn)程,進(jìn)程的pid分別是2829、2831、2836,其中2829是2831的父進(jìn)程,而2831又是2836的父進(jìn)程。


所以,其實(shí)我們雖然看起來(lái)只是啟動(dòng)了一個(gè)Server,其實(shí)最后產(chǎn)生的是三個(gè)進(jìn)程。


這三個(gè)進(jìn)程中,所有進(jìn)程的根進(jìn)程,也就是例子中的2829進(jìn)程,就是所謂的Master進(jìn)程;而2831進(jìn)程,則是Manager進(jìn)程;最后的2836進(jìn)程,是Worker進(jìn)程。


基于此,我們簡(jiǎn)單梳理一下,當(dāng)執(zhí)行的start方法之后,發(fā)生了什么:


守護(hù)進(jìn)程模式下,當(dāng)前進(jìn)程fork出Master進(jìn)程,然后退出,Master進(jìn)程觸發(fā)OnMasterStart事件。


Master進(jìn)程啟動(dòng)成功之后,fork出Manager進(jìn)程,并觸發(fā)OnManagerStart事件。


Manager進(jìn)程啟動(dòng)成功時(shí)候,fork出Worker進(jìn)程,并觸發(fā)OnWorkerStart事件。


非守護(hù)進(jìn)程模式下,則當(dāng)前進(jìn)程直接作為Master進(jìn)程工作。


所以,一個(gè)最基礎(chǔ)的Swoole Server,至少需要有3個(gè)進(jìn)程,分別是Master進(jìn)程、Manager進(jìn)程和Worker進(jìn)程。


不要看到進(jìn)程多就覺(jué)得麻煩咯,其實(shí)全賴它們各司其職,才有Swoole重新定義PHP的壯舉。


事實(shí)上,一個(gè)多進(jìn)程模式下的Swoole Server中,有且只有一個(gè)Master進(jìn)程;有且只有一個(gè)Manager進(jìn)程;卻可以有n個(gè)Worker進(jìn)程。


那么這幾個(gè)進(jìn)程之間是怎么協(xié)同工作的呢?我們先暫時(shí)考慮只有一個(gè)Worker的情況。


那么,我們又可以拉出之前寫(xiě)的最簡(jiǎn)單Server,來(lái)看看這個(gè)過(guò)程中,三種進(jìn)程之間是怎么協(xié)作的。


Client主動(dòng)Connect的時(shí)候,Client實(shí)際上是與Master進(jìn)程中的某個(gè)Reactor線程發(fā)生了連接。


當(dāng)TCP的三次握手成功了以后,由這個(gè)Reactor線程將連接成功的消息告訴Manager進(jìn)程,再由Manager進(jìn)程轉(zhuǎn)交給Worker進(jìn)程。


在這個(gè)Worker進(jìn)程中觸發(fā)了OnConnect的方法。


當(dāng)Client向Server發(fā)送了一個(gè)數(shù)據(jù)包的時(shí)候,首先收到數(shù)據(jù)包的是Reactor線程,同時(shí)Reactor線程會(huì)完成組包,再將組好的包交給Manager進(jìn)程,由Manager進(jìn)程轉(zhuǎn)交給Worker。


此時(shí)Worker進(jìn)程觸發(fā)OnReceive事件。


如果在Worker進(jìn)程中做了什么處理,然后再用Send方法將數(shù)據(jù)發(fā)回給客戶端時(shí),數(shù)據(jù)則會(huì)沿著這個(gè)路徑逆流而上。


同樣的故事,隨著認(rèn)識(shí)的加深,會(huì)發(fā)現(xiàn)不一樣的精彩


首先,Master進(jìn)程是一個(gè)多線程進(jìn)程,其中有一組非常重要的線程,叫做Reactor線程(組),每當(dāng)一個(gè)客戶端連接上服務(wù)器的時(shí)候,都會(huì)由Master進(jìn)程從已有的Reactor線程中,根據(jù)一定規(guī)則挑選一個(gè),專門(mén)負(fù)責(zé)向這個(gè)客戶端提供維持鏈接、處理網(wǎng)絡(luò)IO與收發(fā)數(shù)據(jù)等服務(wù)。


以前我們提到的分包拆包等功能也是在這里完成的哦。


而Manager進(jìn)程,某種意義上可以看做一個(gè)代理層,它本身并不直接處理業(yè)務(wù),其主要工作是將Master進(jìn)程中收到的數(shù)據(jù)轉(zhuǎn)交給Worker進(jìn)程,或者將Worker進(jìn)程中希望發(fā)給客戶端的數(shù)據(jù)轉(zhuǎn)交給Master進(jìn)程進(jìn)行發(fā)送。


另外,Manager進(jìn)程還負(fù)責(zé)監(jiān)控Worker進(jìn)程,如果Worker進(jìn)程因?yàn)槟承┮馔鈷炝耍琈anager進(jìn)程會(huì)重新拉起新的Worker進(jìn)程,有點(diǎn)像Supervisor的工作


而這個(gè)特性,也是最終實(shí)現(xiàn)熱重載的核心機(jī)制。


最后就是Worker進(jìn)程了,顧名思義,Worker進(jìn)程其實(shí)就是處理各種業(yè)務(wù)工作的進(jìn)程,Manager將數(shù)據(jù)包轉(zhuǎn)交給Worker進(jìn)程,然后Worker進(jìn)程進(jìn)行具體的處理,并根據(jù)實(shí)際情況將結(jié)果反饋給客戶端。


如果要打個(gè)比方的話,Master進(jìn)程就像業(yè)務(wù)窗口的,Reactor就是前臺(tái)接待員,用戶很多的時(shí)候,后邊的用戶就需要排隊(duì)等待服務(wù);Reactor負(fù)責(zé)與客戶直接溝通,對(duì)客戶的請(qǐng)求進(jìn)行初步的整理(傳輸層級(jí)別的整理——組包);然后,Manager進(jìn)程就是類似項(xiàng)目經(jīng)理的角色,要負(fù)責(zé)將業(yè)務(wù)分配給合適的Worker(例如空閑的Worker);而Worker進(jìn)程就是工人,負(fù)責(zé)實(shí)現(xiàn)具體的業(yè)務(wù)。


實(shí)際上,一對(duì)多投遞這種模式總是在并發(fā)的程序設(shè)計(jì)非常常見(jiàn):1個(gè)Master進(jìn)程投遞n個(gè)Reactor線程;1個(gè)Manager進(jìn)程投遞n個(gè)Worker進(jìn)程。


現(xiàn)在,我們來(lái)看看一個(gè)簡(jiǎn)單的多進(jìn)程Swoole Server的幾個(gè)基本配置:




$server->set([


"daemonize"=>true,


"reactor_num"=>2,


"worker_num"=>4,]


);


$server->start();


reactor_num:表示Master進(jìn)程中,Reactor線程總共開(kāi)多少個(gè),注意,這個(gè)可不是越多越好,因?yàn)橛?jì)算機(jī)的CPU是有限的,所以一般設(shè)置為與CPU核心數(shù)量相同,或者兩倍即可。


worker_num:表示啟動(dòng)多少個(gè)Worker進(jìn)程,同樣,Worker進(jìn)程數(shù)量不是越多越好,仍然設(shè)置為與CPU核心數(shù)量相同,或者兩倍即可。


讀書(shū)萬(wàn)卷不若自己親手寫(xiě)一行,試驗(yàn)一下這個(gè)配置下,Server啟動(dòng)后,pstree的結(jié)構(gòu)。


進(jìn)程模型與數(shù)據(jù)共享


在以前的討論中,我們最常接觸到的回調(diào)方法如下:


OnConnect


OnReceive


OnClose


如上一節(jié)所說(shuō),這三個(gè)回調(diào)其實(shí)都是在Worker進(jìn)程中發(fā)生的,而了解了進(jìn)程模型以后,我們可以認(rèn)識(shí)一下更多的回調(diào)方法了:


// 以下回調(diào)發(fā)生在Master進(jìn)程


$server->on("start",function(\swoole_server$server){


echo"On master start.";


});


$server->on('shutdown',function(\swoole_server$server){


echo"On master shutdown.";


});


// 以下回調(diào)發(fā)生在Manager進(jìn)程


$server->on('ManagerStart',function(\swoole_server$server){


echo"On manager start.";


});


$server->on('ManagerStop',function(\swoole_server$server){


echo"On manager stop.";


});


// 以下回調(diào)也發(fā)生在Worker進(jìn)程


$server->on('WorkerStart',function(\swoole_server$server,$worker_id){


echo"Worker start";


});


$server->on('WorkerStop',function(\swoole_server$server,$worker_id){


echo"Worker stop";


});


$server->on('WorkerError',function(\swoole_server$server,$worker_id,$worker_pid,$exit_code){


echo"Worker error";


});


OK,現(xiàn)在我們更新一下我們的測(cè)試代碼,以展示不同進(jìn)程之間,數(shù)據(jù)共享的特點(diǎn)和關(guān)系:


$server=new\swoole_server("127.0.0.1",8088,SWOOLE_PROCESS,SWOOLE_SOCK_TCP);


$server->on('connect',function($serv,$fd){ });


$server->on('receive',function($serv,$fd,$from_id,$data){ });


$server->on('close',function($serv,$fd){ });


// 在交互進(jìn)程中放入一個(gè)數(shù)據(jù)。


$server->BaseProcess="I'm base process."http:// 為了便于閱讀,以下回調(diào)方法按照被起調(diào)的順序組織


// 1. 首先啟動(dòng)Master進(jìn)程


$server->on("start",function(\swoole_server$server){


echo"On master start.".PHP_EOL;


// 先打印在交互進(jìn)程寫(xiě)入的數(shù)據(jù)


echo"server->BaseProcess =".$server->BaseProcess.PHP_EOL;


// 修改交互進(jìn)程中寫(xiě)入的數(shù)據(jù)


$server->BaseProcess="I'm changed by master.";


// 在Master進(jìn)程中寫(xiě)入一些數(shù)據(jù),以傳遞給Manager進(jìn)程。


$server->MasterToManager="Hello manager, I'm master.";


});


// 2. Master進(jìn)程拉起Manager進(jìn)程


$server->on('ManagerStart',function(\swoole_server$server){


echo"On manager start.".PHP_EOL;


// 打印,然后修改交互進(jìn)程中寫(xiě)入的數(shù)據(jù)


echo"server->BaseProcess =".$server->BaseProcess.PHP_EOL;


$server->BaseProcess="I'm changed by manager.";


// 打印,然后修改在Master進(jìn)程中寫(xiě)入的數(shù)據(jù)


echo"server->MasterToManager =".$server->MasterToManager.PHP_EOL;


$server->MasterToManager="This value has changed in manager.";


// 寫(xiě)入傳遞給Worker進(jìn)程的數(shù)據(jù)


$server->ManagerToWorker="Hello worker, I'm manager.";


});


// 3. Manager進(jìn)程拉起Worker進(jìn)程


$server->on('WorkerStart',function(\swoole_server$server,$worker_id){


echo"Worker start".PHP_EOL;


// 打印在交互進(jìn)程寫(xiě)入,然后在Master進(jìn)程,又在Manager進(jìn)程被修改的數(shù)據(jù)


echo"server->BaseProcess =".$server->BaseProcess.PHP_EOL;


// 打印,并修改Master寫(xiě)入給Manager的數(shù)據(jù)


echo"server->MasterToManager =".$server->MasterToManager.PHP_EOL;


$server->MasterToManager="This value has changed in worker.";


// 打印,并修改Manager傳遞給Worker進(jìn)程的數(shù)據(jù)


echo"server->ManagerToWorker =".$server->ManagerToWorker.PHP_EOL;


$server->ManagerToWorker="This value is changed in worker.";


});


// 4. 正常結(jié)束Server的時(shí)候,首先結(jié)束Worker進(jìn)程


$server->on('WorkerStop',function(\swoole_server$server,$worker_id){


echo"Worker stop".PHP_EOL;


// 分別打印之前的數(shù)據(jù)


echo"server->ManagerToWorker =".$server->ManagerToWorker.PHP_EOL;


echo"server->MasterToManager =".$server->MasterToManager.PHP_EOL;


echo"server->BaseProcess =".$server->BaseProcess.PHP_EOL;


});


// 5. 緊接著結(jié)束Manager進(jìn)程


$server->on('ManagerStop',function(\swoole_server$server){


echo"Manager stop.".PHP_EOL;


// 分別打印之前的數(shù)據(jù)


echo"server->ManagerToWorker =".$server->ManagerToWorker.PHP_EOL;


echo"server->MasterToManager =".$server->MasterToManager.PHP_EOL;


echo"server->BaseProcess =".$server->BaseProcess.PHP_EOL;


});


// 6. 最后回收Master進(jìn)程


$server->on('shutdown',function(\swoole_server$server){


echo"Master shutdown.".PHP_EOL;


// 分別打印之前的數(shù)據(jù)


echo"server->ManagerToWorker =".$server->ManagerToWorker.PHP_EOL;


echo"server->MasterToManager =".$server->MasterToManager.PHP_EOL;


echo"server->BaseProcess =".$server->BaseProcess.PHP_EOL;


});


$server->start();


這段程序測(cè)試的時(shí)候,我們需要開(kāi)兩個(gè)會(huì)話,第一個(gè)會(huì)話用于執(zhí)行并打印輸出;第二個(gè)會(huì)話用于使用kill命令通知Server執(zhí)行一些工作,然后我們看看輸出的結(jié)果:


# 在會(huì)話一中>php swoole_server_demo.phpOn master start.server->BaseProcess = I'm base process.


On manager start.


server->BaseProcess = I'm base process.server->MasterToManager = Worker startserver->BaseProcess = I'm base process.


server->MasterToManager =


server->ManagerToWorker =


從Manager start和Worker start中的輸出,我們發(fā)現(xiàn)BaseProcess、MasterToManager、ManagerToWorker并沒(méi)有分別在Master、Manager中被修改,并在子進(jìn)程中打印出被修改后的結(jié)果,這是為什么呢?別急,我們繼續(xù)做個(gè)實(shí)驗(yàn)。


打開(kāi)會(huì)話二,先執(zhí)行pstree -ap|grep php找到剛剛啟動(dòng)的Server的Master進(jìn)程的PID,然后向該進(jìn)程發(fā)送-10信號(hào),然后再次實(shí)行pstree命令看看:


>pstree -ap|grep php


||`-php,5512 swoole_server_demo.php


|||-php,5513 swoole_server_demo.php


|||`-php,5515 swoole_server_demo.php


>kill-10 5512


>pstree -ap|grep php


||`-php,5512 swoole_server_demo.php


|||-php,5513 swoole_server_demo.php


|||`-php,5522 swoole_server_demo.php


-10信號(hào)的作用是,要求Swoole重啟Worker服務(wù),我們會(huì)發(fā)現(xiàn)原來(lái)的Worker[5515]被干掉了,而產(chǎn)生了一個(gè)新的Worker[5522],此時(shí)如果我們切換回會(huì)話一,會(huì)發(fā)現(xiàn)增加了以下的輸出:


[2016-10-03 02:00:26$5513.0] ? NOTICE ?Server is reloading now.Worker stopserver->ManagerToWorker = This value is changedinworker.server->MasterToManager = This value has changedinworker.server->BaseProcess = I'm base process.


Worker start


server->BaseProcess = I'm changed by manager.server->MasterToManager = This value has changedinmanager.server->ManagerToWorker = Hello worker, I'm manager.


首先是Swoole自己打印的日志信息,Server正在被reloading,然后Worker[5515]被終止,執(zhí)行了WorkerStop的方法,此時(shí)WorkerStop輸出的值我們可以看出,在WorkerStart中的賦值都是生效了的;然后,新的Worker[5522]被啟動(dòng)了,重新觸發(fā)WorkerStart方法,這時(shí)我們發(fā)現(xiàn),BaseProcess、MasterToManager和ManagerToWorker都分別被打印了出來(lái)?這是什么原因呢?


原因在方法被執(zhí)行的順序上,我們前文中的進(jìn)程起調(diào)順序并沒(méi)有問(wèn)題,但有些地方我們要做一點(diǎn)小小的細(xì)化:


Master進(jìn)程被啟動(dòng)。


Manager進(jìn)程Master進(jìn)程fork出來(lái)。


Worker進(jìn)程被Manager進(jìn)程fork出來(lái)。


MasterStart被回調(diào)。


ManangerStart被回調(diào)。


WorkerStart被回調(diào)。


也就是說(shuō),三種進(jìn)程的OnStart方法被回調(diào)的時(shí)候都有一定的延遲,底層事實(shí)上已經(jīng)完工了fork的行為,才回調(diào)的,因此,默認(rèn)啟動(dòng)的時(shí)候,我們?cè)贠nMasterStart、OnManagerStart中寫(xiě)入的數(shù)據(jù)并不能按預(yù)期被fork到Manager進(jìn)程或者Worker進(jìn)程。


然后,我們執(zhí)行了kill -10重新拉起Worker進(jìn)程的時(shí)候,此時(shí)Worker進(jìn)程仍然是由Mananger進(jìn)程fork出來(lái)的,但此時(shí)ManangerStart已經(jīng)被執(zhí)行過(guò)了,所以我們會(huì)發(fā)現(xiàn)在OnWorkerStart的時(shí)候,輸出變成了ManagerStart中修改過(guò)的內(nèi)容。


OK,現(xiàn)在我們回到Shell會(huì)話二,向Master進(jìn)程發(fā)送kill -15命令


>kill-15 5512


然后回到會(huì)話一,我們發(fā)現(xiàn)輸出增加了如下的內(nèi)容:


[2016-10-03 02:17:35#5512.0] ? NOTICE ?Server is shutdown now.Worker stopserver->ManagerToWorker=This value is changedinworker.server->MasterToManager=This value has changedinworker.server->BaseProcess=I'm changed by manager.


Manager stop.


server->ManagerToWorker = Hello worker, I'm manager.server->MasterToManager=This value has changedinmanager.server->BaseProcess=I'm changed by manager.


Master shutdown.


server->ManagerToWorker =


server->MasterToManager = Hello manager, I'm master.server->BaseProcess=I'm changed by master.


kill -15命令是通知Swoole正常終止服務(wù),首先停止Worker進(jìn)程,觸發(fā)OnWorkerStop回調(diào),此時(shí)我們輸出的內(nèi)容懂事我們?cè)赪orkerStart中修改過(guò)的版本。


然后停止Manager進(jìn)程,這時(shí)候要留意,我們?cè)赪orker中做的所有操作并沒(méi)有反應(yīng)在Manager進(jìn)程上,OnManagerStop的輸出仍然是在OnManagerStart中賦值的內(nèi)容。


最后停止Master進(jìn)程,也會(huì)有相同的事情發(fā)生。


通過(guò)以上實(shí)驗(yàn),展示了多進(jìn)程Server的兩個(gè)重要特性:


父進(jìn)程fork出子進(jìn)程的時(shí)候,子進(jìn)程會(huì)拷貝一份父進(jìn)程的所有數(shù)據(jù)。


各個(gè)進(jìn)程之間的數(shù)據(jù)一般情況下是不共享內(nèi)存的。


所以,學(xué)習(xí)Swoole的進(jìn)一步需求就是,要弄清楚各個(gè)回調(diào)方法分別是在哪個(gè)進(jìn)程中發(fā)生的,且發(fā)生的順序是什么。


這兩個(gè)特性會(huì)引起什么問(wèn)題呢?如果沒(méi)有弄清楚當(dāng)前的代碼是在哪個(gè)進(jìn)程執(zhí)行的,很有可能就會(huì)引起數(shù)據(jù)的錯(cuò)誤,而多個(gè)進(jìn)程之間進(jìn)行協(xié)作的話,不能像以往的PHP開(kāi)發(fā)一樣,通過(guò)共享變量實(shí)現(xiàn)。


以上例子中,為了便于輸出,沒(méi)有啟用守護(hù)進(jìn)程模式,所以交互進(jìn)程與Master進(jìn)程是同一個(gè)進(jìn)程,有興趣的童鞋歡迎在守護(hù)進(jìn)程下實(shí)驗(yàn)。


所以,這又引出了下一個(gè)問(wèn)題,多進(jìn)程模型中,內(nèi)存不能共享,那進(jìn)程之間應(yīng)該怎么通訊呢?限于篇幅,今天我們先討論到這里,下一期我們?cè)賮?lái)探討這個(gè)問(wèn)題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 前言 前文再續(xù),就書(shū)接上一回,隨著與Server、TCP、Protocol的邂逅,Swoole終于迎來(lái)了自己的故事...
    零一間閱讀 5,305評(píng)論 0 17
  • swoole 中的swerver,一個(gè)異步服務(wù)器程序,支持TCP、UDP、UnixSocket 3種協(xié)議,僅需要設(shè)...
    小小小胡閱讀 727評(píng)論 0 0
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,915評(píng)論 18 139
  • 本文示例代碼詳見(jiàn):https://github.com/52fhy/swoole_demo。 簡(jiǎn)介 Swoole是...
    jiancaigege閱讀 844評(píng)論 1 6
  • 關(guān)于“弄柴”這個(gè)叫法,曾經(jīng)在一篇文字里作過(guò)未經(jīng)考證的猜測(cè):當(dāng)年農(nóng)村人多柴少,快意砍柴沒(méi)有可能,四處弄柴倒是事實(shí),雜...
    渝夫2016閱讀 361評(píng)論 0 2