摘要:而爬蟲一般用多線程來控制并發(fā),然而如果是爬蟲,由于其單線程無阻塞性質(zhì)以及事件循環(huán)機(jī)制,一般不用多線程來控制并發(fā)當(dāng)然也可以實(shí)現(xiàn)多線程,此處非重點(diǎn)不再多講,而是更加簡(jiǎn)便地直接在代碼層級(jí)上實(shí)現(xiàn)并發(fā)。下面我們用行代碼實(shí)現(xiàn)一個(gè)并發(fā)控制的函數(shù)。
前言
首發(fā)于 github blog
做過爬蟲的都知道,要控制爬蟲的請(qǐng)求并發(fā)量,其實(shí)也就是控制其爬取頻率,以免被封IP,還有的就是以此來控制爬蟲應(yīng)用運(yùn)行內(nèi)存,否則一下子處理N個(gè)請(qǐng)求,內(nèi)存分分鐘會(huì)爆。
而 python爬蟲一般用多線程來控制并發(fā),
然而如果是node.js爬蟲,由于其單線程無阻塞性質(zhì)以及事件循環(huán)機(jī)制,一般不用多線程來控制并發(fā)(當(dāng)然node.js也可以實(shí)現(xiàn)多線程,此處非重點(diǎn)不再多講),而是更加簡(jiǎn)便地直接在代碼層級(jí)上實(shí)現(xiàn)并發(fā)。
為圖方便,開發(fā)者在開發(fā)node爬蟲一般會(huì)找一個(gè)并發(fā)控制的npm包,然而第三方的模塊有時(shí)候也并不能完全滿足我們的特殊需求,這時(shí)候我們可能就需要一個(gè)自己定制版的并發(fā)控制函數(shù)。
下面我們用15行代碼實(shí)現(xiàn)一個(gè)并發(fā)控制的函數(shù)。
具體實(shí)現(xiàn) 參數(shù)首先,一個(gè)基本的并發(fā)控制函數(shù),基本要有以下3個(gè)參數(shù):
list {Array} - 要迭代的數(shù)組
limit {number} - 控制的并發(fā)數(shù)量
asyncHandle {function} - 對(duì)list的每一個(gè)項(xiàng)的處理函數(shù)
設(shè)計(jì)以下以爬蟲為實(shí)例進(jìn)行講解
設(shè)計(jì)思路其實(shí)很簡(jiǎn)單,假如并發(fā)量控制是 5
首先,瞬發(fā) 5 個(gè)異步請(qǐng)求,我們就得到了并發(fā)的 5 個(gè)異步請(qǐng)求
// limit = 5 while(limit--) { handleFunction(list) }
然后,這 5 個(gè)異步請(qǐng)求中無論哪一個(gè)先執(zhí)行完,都會(huì)繼續(xù)執(zhí)行下一個(gè)list項(xiàng)
let recursion = (arr) => { return asyncHandle(arr.shift()) .then(()=>{ // 迭代數(shù)組長度不為0, 遞歸執(zhí)行自身 if (arr.length!==0) return recursion(arr) // 迭代數(shù)組長度為0,結(jié)束 else return "finish"; }) }
等list所有的項(xiàng)迭代完之后的回調(diào)
return Promise.all(allHandle)代碼
上述步驟組合起來,就是
/** * @params list {Array} - 要迭代的數(shù)組 * @params limit {Number} - 并發(fā)數(shù)量控制數(shù) * @params asyncHandle {Function} - 對(duì)`list`的每一個(gè)項(xiàng)的處理函數(shù),參數(shù)為當(dāng)前處理項(xiàng),必須 return 一個(gè)Promise來確定是否繼續(xù)進(jìn)行迭代 * @return {Promise} - 返回一個(gè) Promise 值來確認(rèn)所有數(shù)據(jù)是否迭代完成 */ let mapLimit = (list, limit, asyncHandle) => { let recursion = (arr) => { return asyncHandle(arr.shift()) .then(()=>{ if (arr.length!==0) return recursion(arr) // 數(shù)組還未迭代完,遞歸繼續(xù)進(jìn)行迭代 else return "finish"; }) }; let listCopy = [].concat(list); let asyncList = []; // 正在進(jìn)行的所有并發(fā)異步操作 while(limit--) { asyncList.push( recursion(listCopy) ); } return Promise.all(asyncList); // 所有并發(fā)異步操作都完成后,本次并發(fā)控制迭代完成 }測(cè)試demo
模擬一下異步的并發(fā)情況
var dataLists = [1,2,3,4,5,6,7,8,9,11,100,123]; var count = 0; mapLimit(dataLists, 3, (curItem)=>{ return new Promise(resolve => { count++ setTimeout(()=>{ console.log(curItem, "當(dāng)前并發(fā)量:", count--) resolve(); }, Math.random() * 5000) }); }).then(response => { console.log("finish", response) })
結(jié)果如下:
手動(dòng)拋出異常中斷并發(fā)函數(shù)測(cè)試:
var dataLists = [1,2,3,4,5,6,7,8,9,11,100,123]; var count = 0; mapLimit(dataLists, 3, (curItem)=>{ return new Promise((resolve, reject) => { count++ setTimeout(()=>{ console.log(curItem, "當(dāng)前并發(fā)量:", count--) if(curItem > 4) reject("error happen") resolve(); }, Math.random() * 5000) }); }).then(response => { console.log("finish", response) })
并發(fā)控制情況下,迭代到5,6,7 手動(dòng)拋出異常,停止后續(xù)迭代:
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/107238.html
摘要:編寫異步代碼可能是一種不同的體驗(yàn),尤其是對(duì)異步控制流而言。回調(diào)函數(shù)的準(zhǔn)則在編寫異步代碼時(shí),要記住的第一個(gè)規(guī)則是在定義回調(diào)時(shí)不要濫用閉包。為回調(diào)創(chuàng)建命名函數(shù),避免使用閉包,并將中間結(jié)果作為參數(shù)傳遞。 本系列文章為《Node.js Design Patterns Second Edition》的原文翻譯和讀書筆記,在GitHub連載更新,同步翻譯版鏈接。 歡迎關(guān)注我的專欄,之后的博文將在專...
摘要:表級(jí)鎖表級(jí)鎖表級(jí)別的鎖定是各存儲(chǔ)引擎中最大顆粒度的鎖定機(jī)制。當(dāng)前沒有其他事務(wù)持有表中任意一行的排他鎖。為了檢測(cè)是否滿足第二個(gè)條件,事務(wù)必須在確保表不存在任何排他鎖的前提下,去檢測(cè)表中的每一行是否存在排他鎖。一、表級(jí)鎖、行級(jí)鎖、頁級(jí)鎖數(shù)據(jù)庫鎖定機(jī)制簡(jiǎn)單來說,就是數(shù)據(jù)庫為了保證數(shù)據(jù)的一致性,而使各種共享資源在被并發(fā)訪問變得有序所設(shè)計(jì)的一種規(guī)則。MySQL數(shù)據(jù)庫由于其自身架構(gòu)的特點(diǎn),存在多種數(shù)據(jù)存...
摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡(jiǎn)介現(xiàn)在,越來越多的科技公司和開發(fā)者開始使用開發(fā)各種應(yīng)用。 說明 2017-12-14 我發(fā)了一篇文章《沒用過Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車的還坐過站了。大家可以很...
摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡(jiǎn)介現(xiàn)在,越來越多的科技公司和開發(fā)者開始使用開發(fā)各種應(yīng)用。 說明 2017-12-14 我發(fā)了一篇文章《沒用過Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車的還坐過站了。大家可以很...
閱讀 3844·2023-04-25 16:32
閱讀 2225·2021-09-28 09:36
閱讀 2043·2021-09-06 15:02
閱讀 683·2021-09-02 15:21
閱讀 930·2019-08-30 15:56
閱讀 3526·2019-08-30 15:45
閱讀 1720·2019-08-30 13:09
閱讀 391·2019-08-29 16:05