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

Как создать неблокирующую асинхронную функцию в node.js?

Как создать неблокирующую асинхронную функцию? Ниже я пытаюсь достичь, но моя программа все еще блокирует...

var sys = require("sys");

function doSomething() {
  sys.puts("why does this block?");
  while(true);
}

setTimeout(doSomething,0);
setTimeout(doSomething,0);
setTimeout(doSomething,0);

sys.puts("main");
4b9b3361

Ответ 1

Отправлено через Reddit.


Цель асинхронных функций в JavaScript немного отличается от того, что вы ищете.

Помните, что JavaScript однопоточный - он может делать только одно за раз. Вот какой-то традиционный, блокирующий код:

sys.puts("Before");
sleep(10);
sys.puts("After");

В реальном веб-приложении sleep() вместо этого может быть трудоемким вызовом базы данных, сетевым запросом (например, ожиданием данных из пользовательского веб-браузера), вспомогательным инструментом или доступом к файлам.

Если вы использовали блокирующие вызовы, подобные описанному выше, сервер Node.js мог бы делать что-либо еще (например, начать обрабатывать другие веб-запросы) во время ожидания.

PHP и многие другие среды веб-программирования справляются с этим, создавая полностью отдельные потоки для каждого запроса. Node.js использует функции обратного вызова. Вы могли бы написать тот же код, как это, вместо этого:

sys.puts("Before");
setTimeout(function(){
    sys.puts("After");
}, 10000);

Здесь вы создаете функцию и передаете ее в setTimeout(). Его код еще не запущен, но когда это произойдет, он получит доступ ко всей области (все переменные), где она была создана. setTimeout() получает ссылку на функцию и расписывает событие для запуска цикла событий после истечения таймаута.

Цикл событий, по сути, представляет собой список задач Node.js(они общие - все приложения GUI, запущенные на вашем компьютере, возможно, используют циклы событий!).

После вызова setTimeout() текущая функция продолжает выполнение. В итоге он возвращается, и функция, которая вызвала его, возвращается и так далее, пока программа не вернется в цикл событий. Цикл событий смотрит, произошло ли что-либо (например, входящий запрос) во время выполнения вашего кода и вызывает соответствующую функцию в вашем коде. Если нет, он ждет, пока что-то не произойдет (например, истечет время ожидания).

Асинхронный код не позволяет вашему коду делать много вещей одновременно, он устраняет блокировку, когда какой-то код зависит от чего-то внешнего, чтобы продолжить.

Редко, что вам нужно делать блокирующие работы внутри вашей программы Node.js. Если вы это сделаете, вы должны разделить эту работу на отдельный процесс (который может даже быть другой программой Node.js) или написать аддон C/С++, который может свободно использовать потоки.

Ответ 2

Вы можете выполнять асинхронный ввод-вывод только в node.js с помощью асинхронных функций ввода-вывода, предоставляемых с помощью node.js runtime или node.js-расширений, написанных на С++. Ваш собственный Javascript-код всегда синхронно в node.js. Асинхронный не-IO-код редко необходим, и дизайнеры node.js решили вообще избежать этого.

Есть несколько тайных способов запуска Javascript асинхронно в node.js, упомянутых другими комментаторами, но node.js не предназначен для такого типа работы. Используйте Erlang, если вам нужен этот тип concurrency, node.js - это только параллон IO, а для параллельных вычислений он так же плох, как Python или PHP.

Ответ 3

Вам нужно запустить функцию блокировки в отдельном процессе.

Этот модуль может помочь: http://github.com/cramforce/node-worker

Ответ 4

Если вы не хотите использовать WebWorker API/ node -работник, который по-прежнему очень альфа, просто создайте дополнительную программу node и обменивайтесь данными через TCP или HTTP.

Это позволяет отправлять вашу работу в виде HTTP-вызовов или необработанных данных TCP и асинхронно ждать ответа HTTP-ответа/входящего TCP.

Обратите внимание, что это подходит только в том случае, если ваша задача легко сериализуема.

Ответ 5

setTimeout не создаст новый поток, поэтому браузер все равно будет висел в бесконечном цикле.

Вам нужно переосмыслить структуру вашей программы.

Ответ 6

Вы можете сделать это, не используя дочерний процесс, используя nextTick()

Я только что прочитал это объяснение на днях о nextTick... это отличная версия IMO

http://howtonode.org/understanding-process-next-tick

Ответ 7

Если я понимаю, что вам нужно, у вас есть две функции (оба принимают обратный вызов как аргумент):

process.nextTick: эта функция может быть уложена в стопку, что означает, что если она вызывается рекурсивно, она будет зацикливать огромное количество (process.maxTickDepth) раз за галочку цикла события.

или

setImmediate: эта функция намного ближе к установке таймаута 0 (но происходит раньше).

В большинстве случаев вам следует выбрать setImmediate.

Ответ 8

Я предполагаю, что вы экспериментируете с Nodejs, также я предполагаю, что вы не пишете сам модуль npm и не экспортируете свою функцию как асинхронную функцию. Практически вы не столкнетесь с таким случаем, если вы хотите делать какие-либо блокирующие операции в функции или обратные вызовы, которые выполняются в среде с одним потоком, пытаются использовать соответствующие модули node, такие как fs для чтения файлов, запрос сетевого запроса и асинхронный модуль, который дает различные типы асинхронных операций, также помните, что вы пытаетесь выполнить процессор, потребляющий код асинхронно, это плохая идея, потому что 2HZ может выполнить миллион строк кода всего за несколько микросекунд

Основная цель nodejs - решить проблему, которую вы задали в вопросе, который обрабатывается базовым libuv для обработки асинхронных событий, я ценю ответ на использование установленного тайм-аута, но вы не знаете, сколько времени подождать или использовать node рабочий в порядке, но вы в конечном итоге напишите много кода плиты котла, так что просто найдите модуль npm, который удовлетворит ваши потребности.

Ответ 9

Эта строка:

while(true);

не "блокирует", он просто занят, навсегда.