限制 Node.js 中的异步调用
Posted
技术标签:
【中文标题】限制 Node.js 中的异步调用【英文标题】:Limiting asynchronous calls in Node.js 【发布时间】:2012-03-21 08:17:06 【问题描述】:我有一个 Node.js 应用程序,它在本地获取文件列表并将它们上传到服务器。此列表可能包含数千个文件。
for (var i = 0; i < files.length; i++)
upload_file(files[i]);
如果我对数千个文件执行此操作,upload_file 将同时被调用数千次,并且很可能会死掉(或者至少是挣扎)。在同步世界中,我们将创建一个线程池并将其限制为一定数量的线程。有没有一种简单的方法来限制一次执行多少个异步调用?
【问题讨论】:
一个类似但速率限制(每秒/分钟)在这里:***.com/questions/20253425/… 这甚至是一个问题的事实是我不喜欢 Node.js 的原因 【参考方案1】:您应该尝试排队。我假设upload_file()
完成时会触发回调。像这样的东西应该可以解决问题(未经测试):
function upload_files(files, maxSimultaneousUploads, callback)
var runningUploads = 0,
startedUploads = 0,
finishedUploads = 0;
function next()
runningUploads--;
finishedUploads++;
if (finishedUploads == files.length)
callback();
else
// Make sure that we are running at the maximum capacity.
queue();
function queue()
// Run as many uploads as possible while not exceeding the given limit.
while (startedUploads < files.length && runningUploads < maxSimultaneousUploads)
runningUploads++;
upload_file(files[startedUploads++], next);
// Start the upload!
queue();
【讨论】:
【参考方案2】:上面的答案,回复:NPM 上的async 是最好的答案,但如果您想了解更多关于控制流的信息:
您应该研究控制流模式。 Chapter 7 of Mixu's Node Book 中有关于控制流模式的精彩讨论。也就是说,我会看 7.2.3 中的示例:有限并行 - 一个异步、并行、并发受限的循环。
我改编了他的例子:
function doUpload()
// perform file read & upload here...
var files = [...];
var limit = 10; // concurrent read / upload limit
var running = 0; // number of running async file operations
function uploader()
while(running < limit && files.length > 0)
var file = files.shift();
doUpload(file, function()
running--;
if(files.length > 0)
uploader();
);
running++;
uploader();
【讨论】:
它工作正常并且只运行指定数量的异步操作;但是我注意到doUpload
内的file
的值(例如running--;
之前)不包含预期值,例如console.log(file)
将在前10 行打印同一个文件10 次(如果@987654328 @ 的值为 10,即)【参考方案3】:
像往常一样,我推荐 Caolan McMahon 的 async module。
让您的upload_file
函数将回调作为第二个参数:
var async = require("async");
function upload_file(file, callback)
// Do funky stuff with file
callback();
var queue = async.queue(upload_file, 10); // Run ten simultaneous uploads
queue.drain = function()
console.log("All files are uploaded");
;
// Queue your files for upload
queue.push(files);
queue.concurrency = 20; // Increase to twenty simultaneous uploads
【讨论】:
我的函数永远不会返回。我收到“所有文件已上传”消息,但我的进程并未终止。【参考方案4】:其他答案似乎已过时。这可以使用async 中的paralleLimit 轻松解决。下面是如何使用它。我没有测试过。
var tasks = files.map(function(f)
return function(callback)
upload_file(f, callback)
);
parallelLimit(tasks, 10, function()
);
【讨论】:
队列函数和parallellimit有区别吗?【参考方案5】:可以用递归来解决。
这个想法是,最初您发送最大允许数量的请求,并且这些请求中的每一个都应该在完成时递归地继续发送自己。
function batchUpload(files, concurrentRequestsLimit)
return new Promise(resolve =>
var responses = [];
var index = 0;
function recursiveUpload()
if (index === files.length)
return;
upload_file(files[index++]).then(r =>
responses.push(r);
if (responses.length === files.length)
resolve(responses);
else
recursiveUpload();
);
for (var i = 0; i < concurrentRequestsLimit; i++)
recursiveUpload();
);
var files = [
'file_1',
'file_2',
'file_3',
...
'file_100'
];
batchUpload(files, 5).then(responses =>
console.log(responses);
);
【讨论】:
以上是关于限制 Node.js 中的异步调用的主要内容,如果未能解决你的问题,请参考以下文章