[英]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.