事情的背景是這樣的,我想一次抓取多個網(wǎng)頁的內(nèi)容,簡單的做法可以是把網(wǎng)址放進數(shù)組里,foreach遍歷出來一個個抓取。但這樣是同步的,耗時比較長,所以我想用異步多進程來實現(xiàn)。
我參考了workman手冊http://doc.workerman.net/faq/async-task.html,寫了類似的代碼。
其中task worker的進程數(shù)是5,實現(xiàn)抓取一個網(wǎng)頁的業(yè)務(wù)。
而主worker的進程數(shù)是1,接收到網(wǎng)址數(shù)組后,比如是25個網(wǎng)址,就建立25個AsyncTcpConnection將它們一一分發(fā)給task worker進行抓取。
代碼運行的結(jié)果返回如下:
(每一行代表一個要抓取的網(wǎng)頁,記錄了執(zhí)行這次抓取的task worker的id,以及抓取的用時)
(最后一行是總用時)
[attach]496[/attach]
這個結(jié)果是我希望得到的結(jié)果,25個網(wǎng)址,5個進程每個分別執(zhí)行了5次,平均每次抓取0.25秒,總用時1.36秒也和0.25*5很接近。
但我發(fā)現(xiàn)類似這種25個任務(wù)平均分配給5個進程的情況很少出現(xiàn)。經(jīng)常出現(xiàn)有的進程執(zhí)行很多次任務(wù),而有的只執(zhí)行1次。甚至會出現(xiàn)25個任務(wù)全都分配給1個進程的情況,這時總用時達到了6秒 ,相當于單進程的做法?
請問使用多進程時是不是要注意什么規(guī)則?
(本人最近剛學習workman,對php的多進程也不太熟,希望各位前輩多指點)
因為workerman的網(wǎng)絡(luò)io是異步非阻塞的,一個進程可以處理多個鏈接的IO事件,包括鏈接事件。
當瞬間給workerman發(fā)起多個異步鏈接時,workerman處理鏈接事件速度處理很快,一個進程瞬間完全可以處理多個鏈接事件,導(dǎo)致鏈接分配不是很均勻,操作系統(tǒng)為了減少進程切換開銷,會盡量用當前占有cpu的進程處理這些鏈接事件,有的進程維持的連接數(shù)多,有的少,導(dǎo)致任務(wù)分配并不是百分百均勻,是正常現(xiàn)象。
有一些方案可以解決這個問題。
比如給Workerman添加一個pauseAccept接口和resumeAccept接口,即在task的onConnect時調(diào)用pauseAccept暫停接受新客戶端鏈接,這樣只會處理當前鏈接的請求,處理完后調(diào)用resumeAccept,繼續(xù)接受其它鏈接請求。
再比如設(shè)計一個進程模型,分成兩種組進程A B,A組進程只負責把異步請求收集起來,放到一個隊列里面,B組進程負責在從隊列里面獲取,這樣也能保證異步任務(wù)請求能夠更快更均勻的被各個進程處理。這個可以看下 https://github.com/walkor/workerman-queue
還有一些其它的方案等待你去探索