成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

15 行代碼實(shí)現(xiàn)并發(fā)控制(javascript)

gyl_coder / 3557人閱讀

摘要:而爬蟲一般用多線程來控制并發(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

相關(guān)文章

  • 《Node.js設(shè)計(jì)模式》基于回調(diào)的異步控制

    摘要:編寫異步代碼可能是一種不同的體驗(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)注我的專欄,之后的博文將在專...

    Chiclaim 評(píng)論0 收藏0
  • 一文詳解MySQL的鎖機(jī)制

    摘要:表級(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ù)存...

    番茄西紅柿 評(píng)論0 收藏2637
  • 【全文】狼叔:如何正確的學(xué)習(xí)Node.js

    摘要:感謝大神的免費(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í)讀那篇文章,竟然坐車的還坐過站了。大家可以很...

    Edison 評(píng)論0 收藏0
  • 【全文】狼叔:如何正確的學(xué)習(xí)Node.js

    摘要:感謝大神的免費(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í)讀那篇文章,竟然坐車的還坐過站了。大家可以很...

    fengxiuping 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<