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