Подтвердить что ты не робот

Ограничение асинхронных вызовов в Node.js

У меня есть приложение Node.js, которое локально загружает список файлов и загружает их на сервер. Этот список может содержать тысячи файлов.

for (var i = 0; i < files.length; i++) {
   upload_file(files[i]);
}

Если я выполняю это с тысячами файлов, upload_file будет вызываться тысячами раз подряд и, скорее всего, умрет (или, по крайней мере, бороться). В синхронном мире мы создали пул потоков и ограничили бы его до определенного количества потоков. Есть ли простой способ ограничить, сколько асинхронных вызовов выполняется сразу?

4b9b3361

Ответ 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(){
});