NodeJs, как создать неблокирующее вычисление

Я пытаюсь создать вокруг себя неблокирующий кусок тяжелых вычислений в nodejs. Возьмите этот пример (лишенный других вещей):

http.createServer(function(req, res) {
    console.log(req.url);
    sleep(10000);
    res.end('Hello World');
}).listen(8080, function() { console.log("ready"); });

Как вы можете себе представить, если я открою сразу два окна браузера, первый будет ждать 10 секунд, а другой будет ждать 20, как и ожидалось. Итак, вооружившись тем, что обратный вызов каким-то асинхронным образом, я удалил сон и вместо этого поставил его:

doHeavyStuff(function() {
    res.end('Hello World');
});

с просто заданной функцией:

function doHeavyStuff(callback) {
    sleep(10000);
    callback();
}

что, конечно, не работает... Я также попытался определить EventEmitter и зарегистрировать его, но основная функция Emitter имеет сон внутри, прежде чем выпустить "done", например, так что все будет работать блок.

Мне интересно, как другие люди писали неблокирующий код... например, модуль mongojs, или child_process.exec не блокируются, а это значит, что где-то в коде либо они развивают процесс в другом потоке, слушать его события. Как я могу воспроизвести это в методе, который, например, имеет длительный процесс?

Я полностью недопонимаю парадигму nodejs?:/

Спасибо!

Обновление: решение (вроде)

Спасибо за ответ Linus, действительно единственный способ - создать дочерний процесс, например, еще один node script:

http.createServer(function(req, res) {
    console.log(req.url);

    var child = exec('node calculate.js', function (err, strout, strerr) {
        console.log("fatto");
        res.end(strout);
    });

}).listen(8080, function() { console.log("ready"); });

Calc.js может занять свое время, чтобы сделать то, что ему нужно, и вернуться. Таким образом, несколько запросов будут выполняться параллельно, так сказать.

Ответ 1

Вы не можете сделать это напрямую, не используя некоторые из модулей ввода-вывода в node (например, fs или net). Если вам нужно выполнить длительное вычисление, я предлагаю вам сделать это в дочернем процессе (например, child_process.fork) или в очереди.

Ответ 2

Это классическое непонимание того, как работает цикл событий.

Это не то, что уникально для node - если у вас долгое время выполняется вычисление в браузере, оно также блокируется. Способ сделать это состоит в том, чтобы разбить вычисление на небольшие куски, которые дают выполнение цикла цикла, позволяя среде JS чередоваться с другими конкурирующими вызовами, но есть только одна вещь, происходящая на одном время.

Демонстрация setImmediate может быть поучительной, и вы можете найти здесь.

Ответ 3

Если вычисление можно разбить на куски, вы можете запланировать выполнение опроса для данных каждые N секунд, а затем после повторения M секунд. Или создайте выделенного ребенка только для этой задачи, чтобы основной поток не блокировался.

Ответ 4

Мы (Microsoft) только что выпустили napajs, который может работать с Node.js, чтобы включить многопоточность сценариев JavaScript в том же процессе,

ваш код будет выглядеть следующим образом:

var napa = require('napajs');

// One-time setup. 
// You can change number of workers per your requirement. 
var zone = napa.zone.create('request-worker-pool', { workers: 4 });

http.createServer(function(req, res) {
    console.log(req.url);

    zone.execute((request) => {
        var result = null;
        // Do heavy computation to get result from request
        // ...
        return result;
    }, [req]).then((result) => {
        res.end(result.value);
    }
}).listen(8080, function() { console.log("ready"); });

Вы можете прочитать этот пост для более подробной информации.