簡體   English   中英

Node.js - 希望在循環中對方法進行 5 次並行調用

[英]Node.js - want 5 parallel calls to a method in a loop

我在 MongoDB 集合中有 1000 個信息文件。 我正在編寫一個查詢來獲取 1000 條記錄,並在一個循環中調用一個函數將該文件下載到本地系統。 因此,下載所有 1000 個文件是一個順序過程。

我希望在下載過程中有一些並行性。 在循環中,我想一次下載10個文件,這意味着我想調用10次下載函數,完成10個文件下載后我想下載接下來的10個文件(這意味着我需要調用下載函數10次)。

我怎樣才能實現這種並行性,或者有沒有更好的方法來做到這一點?

我看到了Kue npm,但是如何實現呢? 順便說一下,我是從 FTP 下載的,所以我使用basic-ftp npm 進行 ftp 操作。

異步庫在這方面非常強大,一旦你了解了基礎知識也很容易。

我建議您使用eachLimit,這樣您的應用程序就不必擔心以十個為一組進行循環,它只會同時下載十個文件。

var files = ['a.txt', 'b.txt']
var concurrency = 10;

async.eachLimit(files, concurrency, downloadFile, onFinish);


function downloadFile(file, callback){

  // run your download code here
  // when file has downloaded, call callback(null)
  // if there is an error, call callback('error code')

}

function onFinish(err, results){

  if(err) {
    // do something with the error
  }

  // reaching this point means the files have all downloaded

}

異步庫將並行運行downloadFile ,從files列表中向每個實例發送一個條目,然后當列表中的每個項目都完成時,它將調用onFinish

沒有看到你的實現,我只能提供一個通用的答案。

假設您的下載函數接收一個 fileId 並返回一個承諾,該承諾在所述文件下載完成后進行解析。 對於這個 POC,我將模擬一個承諾,它將在 200 到 500 毫秒后解析為文件名。

function download(fileindex) {
  return new Promise((resolve,reject)=>{ 
    setTimeout(()=>{ 
      resolve(`file_${fileindex}`);
    },200+300*Math.random());
  });
}

您有 1000 個文件,並希望以 100 次迭代下載它們,每次迭代 10 個文件。

讓我們封裝一些東西。 我將聲明一個接收起始 ID 和大小並返回[N...N+size] ids 的函數

function* range(bucket, size=10) {
    let start = bucket*size, 
        end=start+size;
    for (let i = start; i < end; i++) {
        yield i;
    }
}

您應該創建 100 個“存儲桶”,每個存儲桶包含對 10 個文件的引用。

 let buckets = [...range(0,100)].map(bucket=>{
    return [...range(bucket,10)];
 });

A到此, buckets的內容是:

 [
   [file0 ... file9]
   ...
   [file 990 ... file 999]
 ]

然后,使用for..of (具有異步功能)迭代您的存儲桶

在每次迭代中,使用Promise.all將 10 個調用加入Promise.all以進行download

async function proceed() {
    for await(let bucket of buckets) { // for...of
       await Promise.all(bucket.reduce((accum,fileindex)=>{
           accum.push(download(fileindex)); 
           return accum; 
       },[]));
    }
}

讓我們看一個正在運行的示例(只有 10 個存儲桶,我們在這里都很忙 :D)

 function download(fileindex) { return new Promise((resolve, reject) => { let file = `file_${fileindex}`; setTimeout(() => { resolve(file); }, 200 + 300 * Math.random()); }); } function* range(bucket, size = 10) { let start = bucket * size, end = start + size; for (let i = start; i < end; i++) { yield i; } } let buckets = [...range(0, 10)].map(bucket => { return [...range(bucket, 10)]; }); async function proceed() { let bucketNumber = 0, timeStart = performance.now(); for await (let bucket of buckets) { let startingTime = Number((performance.now() - timeStart) / 1000).toFixed(1).substr(-5), result = await Promise.all(bucket.reduce((accum, fileindex) => { accum.push(download(fileindex)); return accum; }, [])); console.log( `${startingTime}s downloading bucket ${bucketNumber}` ); await result; let endingTime = Number((performance.now() - timeStart) / 1000).toFixed(1).substr(-5); console.log( `${endingTime}s bucket ${bucketNumber++} complete:`, `[${result[0]} ... ${result.pop()}]` ); } } document.querySelector('#proceed').addEventListener('click',proceed);
 <button id="proceed" >Proceed</button>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM