Я начал работать с HTTP-сервером Node.js и очень хотел писать Javascript на стороне сервера, но что-то мешает мне начать использовать Node.js для моего веб-приложения.
Я понимаю всю концепцию асинхронного ввода-вывода, но меня несколько беспокоят крайние случаи, когда процедурный код сильно загружает процессор, такой как манипулирование изображениями или сортировка больших наборов данных.
Насколько я понимаю, сервер будет очень быстрым для простых запросов веб-страниц, таких как просмотр списка пользователей или просмотр блога. Однако, если я хочу написать код с очень высокой загрузкой процессора (например, в административной части), который генерирует графику или изменяет размеры тысяч изображений, запрос будет очень медленным (несколько секунд). Поскольку этот код не является асинхронным, все запросы, поступающие на сервер в течение этих нескольких секунд, будут блокироваться, пока мой медленный запрос не будет выполнен.
Одним из предложений было использование Web Workers для задач с интенсивным использованием процессора. Тем не менее, я боюсь, что веб-работникам будет сложно писать чистый код, поскольку он работает, включая отдельный файл JS. Что если интенсивный процессорный код находится в методе объекта? Это отстойно писать файл JS для каждого метода, интенсивно использующего процессор.
Другое предложение состояло в том, чтобы порождать дочерний процесс, но это делает код еще менее поддерживаемым.
Любые предложения по преодолению этого (предполагаемого) препятствия? Как вы пишете чистый объектно-ориентированный код с Node.js, в то же время гарантируя, что тяжелые задачи процессора выполняются асинхронно?
источник
Ответы:
Что вам нужно, это очередь задач! Перенос ваших долгосрочных задач с веб-сервера - это ХОРОШО. Хранение каждой задачи в «отдельном» файле js способствует модульности и повторному использованию кода. Это заставляет вас задуматься о том, как структурировать вашу программу таким образом, чтобы облегчить ее отладку и сопровождение в долгосрочной перспективе. Еще одно преимущество очереди задач - рабочие могут быть написаны на другом языке. Просто поставьте задачу, сделайте работу и напишите ответ.
что-то вроде этого https://github.com/resque/resque
Вот статья из github о том, почему они ее построили http://github.com/blog/542-introduction-resque
источник
Это неправильное понимание определения веб-сервера - его следует использовать только для «общения» с клиентами. Задачи с высокой нагрузкой следует делегировать автономным программам (это, конечно, можно также написать в JS).
Вы, вероятно, сказали бы, что это грязно, но я уверяю вас, что процесс веб-сервера, застрявший в изменении размеров изображений, только хуже (даже для, скажем, Apache, когда он не блокирует другие запросы). Тем не менее, вы можете использовать общую библиотеку, чтобы избежать избыточности кода.
РЕДАКТИРОВАТЬ: я придумал аналогию; веб-приложение должно быть как ресторан. У вас есть официанты (веб-сервер) и повара (рабочие). Официанты общаются с клиентами и выполняют простые задачи, такие как предоставление меню или объяснение того, является ли какое-то блюдо вегетарианским. С другой стороны, они делегируют более сложные задачи на кухню. Поскольку официанты делают только простые вещи, они быстро реагируют, а повара могут сосредоточиться на своей работе.
Здесь Node.js будет единственным, но очень талантливым официантом, который может обрабатывать много запросов одновременно, а Apache будет бандой тупых официантов, которые будут обрабатывать только один запрос каждый. Если этот официант Node.js начнет готовить, это станет настоящей катастрофой. Тем не менее, приготовление пищи также может истощить даже большое количество официантов Apache, не говоря уже о хаосе на кухне и постепенном снижении чувствительности.
источник
Вы не хотите, чтобы ваш процессор с интенсивным использованием процессора выполнял асинхронно, вы хотите, чтобы он выполнялся параллельно . Вам нужно вывести обработку из потока, который обслуживает HTTP-запросы. Это единственный способ решить эту проблему. С NodeJS ответом является кластерный модуль , чтобы дочерние процессы для выполнения тяжелой работы. (У узла AFAIK нет понятия потоков / разделяемой памяти; это процессы или ничего). У вас есть два варианта структуры вашего приложения. Вы можете получить решение 80/20, создав 8 HTTP-серверов и синхронно обрабатывая ресурсоемкие задачи на дочерних процессах. Делать это довольно просто. Вы можете потратить час, чтобы прочитать об этом по этой ссылке. На самом деле, если вы просто сорвете пример кода в верхней части этой ссылки, вы получите 95% пути.
Другой способ структурировать это - создать очередь заданий и отправить по ней большие вычислительные задачи. Обратите внимание, что с IPC связано много накладных расходов для очереди заданий, поэтому это полезно только тогда, когда задачи заметно превышают накладные расходы.
Я удивлен, что ни один из этих других ответов даже не упоминает кластер.
Предпосылки: асинхронный код - это код, который приостанавливается до тех пор, пока что- то не случится где-то еще , и в этот момент код активируется и продолжает выполнение. Один очень распространенный случай, когда что-то медленное должно произойти где-то еще, - это ввод-вывод.
Асинхронный код бесполезен, если за работу отвечает ваш процессор . Именно так обстоит дело с «интенсивными вычислениями».
Теперь может показаться, что асинхронный код - это ниша, но на самом деле он очень распространен. Просто так бывает не полезно для сложных задач.
Ожидание ввода-вывода - это шаблон, который всегда происходит, например, на веб-серверах. Каждый клиент, который подключается к вашему серверу, получает сокет. В большинстве случаев розетки пусты. Вы не хотите ничего делать, пока сокет не получит некоторые данные, после чего вы захотите обработать запрос. Внутренний HTTP-сервер, такой как Node, использует библиотеку событий (libev) для отслеживания тысяч открытых сокетов. ОС уведомляет libev, а затем libev уведомляет NodeJS, когда один из сокетов получает данные, а затем NodeJS помещает событие в очередь событий, и ваш http-код активируется в этот момент и обрабатывает события одно за другим. События не помещаются в очередь до тех пор, пока в сокете не будет данных, поэтому события никогда не ожидают данных - они уже там.
Однопоточные веб-серверы, основанные на событиях, имеют смысл в качестве парадигмы, когда узкое место ожидает куча в основном пустых соединений сокетов, и вам не нужен целый поток или процесс для каждого простаивающего соединения, и вы не хотите опрашивать свои 250 тыс. сокеты, чтобы найти следующий, который имеет данные на нем.
источник
Пара подходов, которые вы можете использовать.
Как отмечает @Tim, вы можете создать асинхронную задачу, которая находится вне или параллельно вашей основной логике обслуживания. Зависит от ваших точных требований, но даже cron может выступать в качестве механизма очередей.
WebWorkers могут работать для ваших асинхронных процессов, но в настоящее время они не поддерживаются node.js. Есть несколько расширений, которые обеспечивают поддержку, например: http://github.com/cramforce/node-worker
Вы по-прежнему получаете возможность использовать модули и код через стандартный механизм «требуется». Вам просто нужно убедиться, что начальная отправка работнику передает всю информацию, необходимую для обработки результатов.
источник
Использование
child_process
это одно решение. Но каждый порожденный дочерний процесс может потреблять много памяти по сравнению с Gogoroutines
Вы также можете использовать решение на основе очереди, например, Kue
источник