以下分析了php和node如何處理一個(gè)以及多個(gè)Http請(qǐng)求以及代碼中的IO操作處理機(jī)制纸颜。
PHP的實(shí)現(xiàn):
基本流程:
web服務(wù)器接受到請(qǐng)求之后合住,轉(zhuǎn)發(fā)給一個(gè)php解釋器進(jìn)程,進(jìn)程執(zhí)行完代碼并將輸出結(jié)果返回給web服務(wù)器项钮,web服務(wù)器返回給發(fā)起http請(qǐng)求的客戶端华望。
多個(gè)請(qǐng)求時(shí):
php-fpm : 主進(jìn)程接受請(qǐng)求分配給worker進(jìn)程處理,如果當(dāng)前的worker進(jìn)程都在執(zhí)行中狮辽,則適當(dāng)?shù)拈_(kāi)辟新的進(jìn)程的處理一也。但是同一時(shí)刻,每個(gè)進(jìn)程只能處理一個(gè)請(qǐng)求喉脖,當(dāng)多個(gè)請(qǐng)求同時(shí)到達(dá)時(shí)椰苟,則必須開(kāi)辟多個(gè)進(jìn)程才能處理,否則只能挨個(gè)排隊(duì)等待树叽。由于不斷開(kāi)辟進(jìn)程十分消耗系統(tǒng)資源舆蝴,也很容易到達(dá)上限,所以單機(jī)情況下這種模式很難抗住大量的并發(fā)题诵。這種多進(jìn)程模型的優(yōu)點(diǎn)是:當(dāng)某個(gè)進(jìn)程發(fā)生意外過(guò)執(zhí)行時(shí)間過(guò)長(zhǎng)時(shí)洁仗,不會(huì)阻塞住整個(gè)請(qǐng)求處理系統(tǒng)。
代碼中出現(xiàn)IO調(diào)用時(shí)性锭,如請(qǐng)求數(shù)據(jù)庫(kù)或者請(qǐng)一個(gè)遠(yuǎn)程文件京痢,php會(huì)一直等待請(qǐng)求結(jié)果或者超時(shí),代碼才能接著向下運(yùn)行篷店,當(dāng)然祭椰,借助一些擴(kuò)展,也可以實(shí)現(xiàn)非阻塞的事件回調(diào)機(jī)制疲陕。
Node的實(shí)現(xiàn):
Node自己實(shí)現(xiàn)了Web服務(wù)器的功能方淤,監(jiān)聽(tīng)服務(wù)器端口等待連接,可以接受很多請(qǐng)求蹄殃,就像nginx那樣携茂。當(dāng)前連接成功并分析完這個(gè)請(qǐng)求后,接下來(lái)就是要處理該做什么了诅岩。假設(shè)每次請(qǐng)求要做一些數(shù)據(jù)的計(jì)算讳苦,同時(shí)接聽(tīng)到100次請(qǐng)求,那這100次運(yùn)算在時(shí)間線上是排隊(duì)處理的吩谦,因?yàn)橹挥幸粋€(gè)node主進(jìn)程在做這件事鸳谜。但是請(qǐng)求中以IO操作為主時(shí),比如每次請(qǐng)求的任務(wù)是到某個(gè)網(wǎng)頁(yè)爬取這個(gè)網(wǎng)頁(yè)的所有圖片式廷,那這100個(gè)請(qǐng)求會(huì)很快全部發(fā)出抓取遠(yuǎn)程圖片的指令咐扭。
如果是阻塞式IO,則當(dāng)前進(jìn)程內(nèi)一個(gè)請(qǐng)求拿到結(jié)果后才能發(fā)起下一個(gè)請(qǐng)求。Node的IO操作是異步的,IO操作沒(méi)有拿到結(jié)果的時(shí)候不會(huì)阻塞住當(dāng)前線程蝗肪,所以可以發(fā)起很多IO請(qǐng)求袜爪。如果把IO操作當(dāng)做攻城的話,就像戰(zhàn)場(chǎng)上的統(tǒng)帥薛闪,同時(shí)向多個(gè)將軍發(fā)出攻城的指令辛馆,然后將軍們各自到自己的路線攻城就可以了。如何有哪路軍隊(duì)作戰(zhàn)完成豁延,就會(huì)匯報(bào)給將軍昙篙,然后執(zhí)行異步的處理。 (阻塞式:向1路軍發(fā)送攻打A城的指令术浪,1路軍打完了,再向2路軍發(fā)送攻打B城的指令...)
Node通過(guò)其事件引擎libuv實(shí)現(xiàn)了線程池來(lái)完成真正的異步IO操作寿酌。(不要和多路復(fù)用IO的概念混淆胰苏,epoll本質(zhì)并非異步)