2010-05-20 2 views
21

Как создать неблокирующую асинхронную функцию? Ниже то, что я пытаюсь достичь, но моя программа по-прежнему блокирует ...Как создать неблокирующую асинхронную функцию в 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"); 

ответ

3

setTimeout не будет создавать новую тему, так что браузер будет еще висеть в бесконечном цикле.

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

+0

Есть ли у вас какие-либо идеи, как я могу достичь этого в node.js? Спасибо – Richard

+1

Этот вопрос довольно старый, но все же очень интересный для новичков node.js, таких как я .. Как упоминалось, node.js предназначен для параллельного ввода-вывода, не параллельного работе. Это означает: если у вас есть трудоемкое задание для ответа на один запрос, узел node.js не ускорит то, что вы пытаетесь достичь в этом единственном запросе. Разница между использованием sleep() и setTimeout() ist заключается в том, что node.js блокирует все остальные запросы при использовании sleep() для времени сна - использование setTimeout() не блокирует другие запросы. Или: 10 запросов на спящий режим (10 секунд) будут принимать 100 с - 10 запросов на setTimeout (10 с) всего 10 секунд. – schlicki

10

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

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

+26

Важно понимать, что узел не о том, что функции все время асинхронны. Это о * i/o *, являющемся асинхронным и неблокирующим. Если ваша функция не выполняет никаких операций ввода-вывода, узел не поможет вам сделать ее асинхронной. Он предоставляет инструменты, которые позволят вам это сделать. Как дочерние процессы. Вот о чем идет речь Феликса. Ваша функция может порождать дочерний процесс для выполнения вашей работы, и он будет выполняться из основного цикла событий. – Marco

-6

Эта строка:

while(true); 

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

4

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

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

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

11

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

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

+0

Отличный ответ, у меня есть один вопрос: Является ли операция mongo db в Node.js асинхронной IO? –

+1

Да. '.connect' и' .insert', например, являются асинхронными функциями. См. Http://mongodb.github.io/node-mongodb-native/2.0/overview/quickstart/ – nponeccop

31

Перекресток с 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() получает ссылку на функцию и расписывает событие, которое должно срабатывать по the event loop после истечения таймаута.

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

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

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

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

+1

А! Теперь я понимаю это более четко. Спасибо за объяснение; ваш третий последний абзац был особенно полезен. +1 –

2

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

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

или

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

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

0

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

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

Смежные вопросы