Ограничение асинхронных вызовов в Node.js
У меня есть приложение Node.js, которое локально загружает список файлов и загружает их на сервер. Этот список может содержать тысячи файлов.
for (var i = 0; i < files.length; i++) {
upload_file(files[i]);
}
Если я выполняю это с тысячами файлов, upload_file будет вызываться тысячами раз подряд и, скорее всего, умрет (или, по крайней мере, бороться). В синхронном мире мы создали пул потоков и ограничили бы его до определенного количества потоков. Есть ли простой способ ограничить, сколько асинхронных вызовов выполняется сразу?
Ответы
Ответ 1
Как обычно, я рекомендую асинхронный модуль Caolan McMahon.
Сделайте вашу функцию 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
Ответ 2
Ответ выше, re: async в NPM - лучший ответ, но если вы хотите узнать больше о потоке управления
Вы должны изучить шаблоны управления потоком. Там замечательная дискуссия о шаблонах управления потоком в Глава 7 Mixu Node Книга. А именно, я бы посмотрел на пример в 7.2.3: Ограниченный параллельный - асинхронный, параллельный, concurrency ограниченный для цикла.
Я приспособил его пример:
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();
Ответ 3
Вы должны попробовать в очереди. Я предполагаю, что обратный вызов запускается, когда 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();
}
Ответ 4
Остальные ответы кажутся устаревшими. Это можно легко решить, используя paralleLimit из async. Ниже приведен пример использования. Я не тестировал его.
var tasks = files.map(function(f) {
return function(callback) {
upload_file(f, callback)
}
});
parallelLimit(tasks, 10, function(){
});