這個(gè)頻道內(nèi)會(huì)詳細(xì)介紹異步編程與同步編程的不同之處以及需要注意的事項(xiàng)。
新手非常容易犯這個(gè)錯(cuò)誤,由于swoole是常駐內(nèi)存的,所以加載類/函數(shù)定義的文件后不會(huì)釋放。因此引入類/函數(shù)的php文件時(shí)必須要使用include_once或require_once,否會(huì)發(fā)生cannot redeclare function/class 的致命錯(cuò)誤。
PHP守護(hù)進(jìn)程與普通Web程序的變量生命周期、內(nèi)存管理方式完全不同。請(qǐng)參考 swoole_server內(nèi)存管理 頁(yè)面。編寫swoole_server或其他常駐進(jìn)程時(shí)需要特別注意。
進(jìn)程隔離也是很多新手經(jīng)常遇到的問(wèn)題。修改了全局變量的值,為什么不生效,原因就是全局變量在不同的進(jìn)程,內(nèi)存空間是隔離的,所以無(wú)效。所以使用swoole開(kāi)發(fā)Server程序需要了解進(jìn)程隔離問(wèn)題。
在異步IO的程序中,不得使用sleep/usleep/time_sleep_until/time_nanosleep。(下文中使用sleep泛指所有睡眠函數(shù))
swoole提供的swoole_event_add、swoole_timer_tick、swoole_timer_after、swoole_process::signal、異步swoole_client 在進(jìn)程sleep后會(huì)停止工作。swoole_server也無(wú)法再處理新的請(qǐng)求。
$serv = new swoole_server("127.0.0.1", 9501); $serv->on('receive', function ($serv, $fd, $from_id, $data) { sleep(100); $serv->send($fd, 'Swoole: '.$data); }); $serv->start();
onReceive事件中執(zhí)行了sleep函數(shù),server在100秒內(nèi)無(wú)法再收到任何客戶端請(qǐng)求。
在swoole程序中禁止使用exit/die,如果PHP代碼中有exit/die,當(dāng)前工作的Worker進(jìn)程、Task進(jìn)程、User進(jìn)程、以及swoole_process進(jìn)程會(huì)立即退出。
建議使用try/catch的方式替換exit/die,實(shí)現(xiàn)中斷執(zhí)行跳出PHP函數(shù)調(diào)用棧。
function swoole_exit($msg) { //php-fpm的環(huán)境 if (ENV=='php') { exit($msg); } //swoole的環(huán)境 else { throw new Swoole\ExitException($msg); } }
異常處理的方式比exit/die更友好,因?yàn)楫惓J强煽氐模?span style="font-family:Consolas, Liberation Mono, Courier, monospace;">exit/die不可控。在最外層進(jìn)行try/catch即可捕獲異常,僅終止當(dāng)前的任務(wù)。Worker進(jìn)程可以繼續(xù)處理新的請(qǐng)求,而exit/die會(huì)導(dǎo)致進(jìn)程直接退出,當(dāng)前進(jìn)程保存的所有變量和資源都會(huì)被銷毀。如果進(jìn)程內(nèi)還有其他任務(wù)要處理,遇到exit/die也將全部丟棄。
異步程序如果遇到死循環(huán),事件將無(wú)法觸發(fā)。異步IO程序使用Reactor模型,運(yùn)行過(guò)程中必須在reactor->wait處輪詢。如果遇到死循環(huán),那么程序的控制權(quán)就在while中了,reactor無(wú)法得到控制權(quán),無(wú)法檢測(cè)事件,所以IO事件回調(diào)函數(shù)也將無(wú)法觸發(fā)。
密集運(yùn)算的代碼不是阻塞
$serv = new swoole_server("127.0.0.1", 9501); $serv->on('receive', function ($serv, $fd, $from_id, $data) { while(1) { $i ++; } $serv->send($fd, 'Swoole: '.$data); }); $serv->start();
onReceive事件中執(zhí)行了死循環(huán),server在無(wú)法再收到任何客戶端請(qǐng)求,必須等待循環(huán)結(jié)束才能繼續(xù)處理新的事件。
更多建議: