16 ноября 2010 в 12:09

Вы наверное шутите, мистер Дал, или почему Node.js — это венец эволюции веб-серверов из песочницы

WTF is Node.js?

Node.js — вещь, вокруг которой сейчас много шума, восторженных отзывов и гневливых выкриков. При этом, по моим наблюдениям, в умах людей закрепилось следующее представление о том что же такое Node.js: «это штука, позволяющая писать на JavaScript на серверной стороне и использующая JavaScript-движок от Google Chrome». Поклонники языка восторженно вздохнули: «Ах! Сбылось!», противники же процедили сквозь зубы: «Ну вот только еще этой ерунды с прототипами и динамической типизацией нам на серверах не хватало!». И дружно побежали ломать копья в блоги и форумы.

При этом многие представители обоих лагерей придерживаются мнения, что Node.js — это эзотерическая игрушка, веселая задумка для переноса языка браузерных сценариев на «новые колеса». Дабы быть до конца честным, признаюсь, что я так же придерживался подобной точки зрения. В один прекрасный момент, я набрался духу и решил «копнуть поглубже». Выяснилось, что создатель Node.js Райан Дал далеко не фанатик, а человек, пытающийся решить реальную проблему. А его творение — не игрушка, а применимое на практике решение.


Так что же такое Node.js? На официальном сайте красуется надпись: «Evented I/O for V8 JavaScript». Не очень то содержательно, верно? Ну что ж, давайте попробуем «изобрести велосипед» и «придумаем» этот самый пресловутый «Evented I/O for V8 JavaScript». Конечно же мы не будем писать никакого кода (бедняге Райану все таки пришлось это делать), а лишь попробуем построить цепочку умозаключений, которые приведут нас к замыслу создания Node.js и тому как он должен быть устроен.

Keep it simple, stupid


Итак, вы знаете, что web-приложения используют клиент-серверную программную модель. Клиентом выступает браузер пользователя, а сервером — например, одна из машин в датацентре некоторого хостера (выберите любого на ваш вкус). Браузер запрашивает какой-то ресурс у сервера, тот, в свою очередь, его отдает клиенту. Такой способ общения клиента и сервера называется «client pull», т. к. клиент буквально дергает (англ. pull) сервер — «Дай-ка мне вон ту страничку, ну дай...». Сервер «обдумывает» ответ на вопрос назойливого клиента и отдает ему его в удобоваримом виде.

Simple web server

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

Parallel universe


Здорово, но такой простейший сервер умеет одновременно общаться лишь с одним пользователем. Если в момент обработки запроса к нему обратиться еще один клиент, то ему придется ждать пока сервер ответит первому. Значит нам нужно распараллелить обработку запросов от пользователей. Очевидное решение: обрабатывать запросы пользователей в отдельных потоках или процессах операционной системы. Давайте назовем каждый такой процесс или поток — worker'ом (англ. рабочий).

Server with threads

В том или ином виде данного подхода придерживаются многие наиболее популярные сегодня веб-серверы (например, Apache и IIS). Данная модель относительно проста в реализации и при этом может удовлетворить потребности большинства малых и средних веб-ресурсов на сегодняшний день.

Но данная модель совершенно не дееспособна, если вам нужно обрабатывать тысячи запросов одновременно. Причин для этого несколько. Во-первых, создание и процессов и потоков — вещь чертовски накладная для любой операционной системы. Но мы можем пойти на хитрость и создавать потоки или процессы заранее и использовать их по мере надобности. OK, мы только что придумали механизмы под названием «thread pool» для потоков и «prefork» для процессов. Это поможет нам не тратить лишний раз ресурсы на создание процессов и потоков, поскольку эта накладная операция может быть выполнена, например, при запуске сервера. Во-вторых, что делать, если все созданные worker'ы заняты? Создать новые? Но мы и так по полной загрузили все ядра процессора нашего сервера, если мы добавим еще несколько потоков или процессов, то они будут конкурировать за процессорное время с уже исполняющимися потоками и процессами. А значит и те и другие будут работать еще медленней. Да, и как отмечалось ранее, создание и обслуживанием потоков и процессов — вещь затратная в плане потребления оперативной памяти и если мы будем создавать поток для каждого из тысячи пользователей, то вскоре можем оказаться в ситуации, когда памяти на сервере попросту не останется, а worker'ы будут находится в состоянии постоянного соревнования за аппаратные ресурсы.

Бесконечность — не предел!


Казалось бы мы оказались в неразрешимой ситуации при имеющихся у нас вычислительных ресурсах. Единственное решение — масштабирование аппаратных ресурсов, что затратно во всех отношениях. Давайте попробуем взглянуть на проблему с другой стороны: чем же заняты большинство наших worker'ов? Они принимают запрос от клиента, создают ответ и отправляют его клиенту. Так где же тут слабое звено? Их здесь целых два — прием запроса от клиента и отправка ответа. Что бы понять что это так, достаточно всего лишь вспомнить среднюю скорость интернет-соединения на сегодняшний день. Но ведь подсистема ввода/вывода может работать в асинхронном режиме, а следовательно может не блокировать worker'ов. Хм, тогда получается фактически единственное чем будут заниматься наши worker'ы — это генерация ответа для клиента и управление заданиями для подсистемы ввода/вывода. Ранее каждый worker мог обслуживать лишь одного клиента одновременно, т. к. брал на себя обязанности по исполнению всего цикла обработки запроса. Теперь же когда сетевой ввод/вывод мы делегировали подсистеме ввода/вывода, то один worker может одновременно обслуживать несколько запросов, например, генерируя ответ для одного клиента, пока ответ для другого отдается подсистемой ввода/вывода. Получается теперь нам не нужно выделять поток для каждого из пользователей, а мы можем создавать по одному worker'у на процессор сервера, предоставляя ему, таким образом, максимум аппаратных ресурсов.

На практике такое делегирование реализуется с использованием парадигмы событийно-ориентированного программирования. Программы, разработанные согласно данной парадигме могут быть реализованы как конечный автомат. Определенные события переводят данный автомат из одного состояния в другое. В нашем случае сервер будет реализован в виде бесконечного цикла, который будет генерировать ответы для клиентов, опрашивать дескрипторы подсистемы ввода/вывода на предмет их готовности для выполнения той или иной операции, и, в случае успеха, передавать им новое задание. Процесс опроса дескрипторов подсистемы ввода/вывода называется «polling». Дело в том, что эффективные реализации polling'а на сегодняшний день имеются лишь в *nix-системах, т.к. последние предоставляют очень быстрые системные вызовы c линейным временем исполнения для данных целей (например, epoll в Linux и kqueue в BSD-системах). Это очень эффективная модель сервера, т. к. позволяет использовать аппаратные ресурсы по-максимуму. Фактически, ни одна из подсистем сервера не простаивает без дела, в чем можно легко убедиться посмотрев на рисунок.

Server with async I/O

Подобную концепцию используют такие серверы, как nginx и lightppd, отлично зарекомендовавшие себя в высоконагруженных системах.

Let's come together


Но (всегда же есть «одно но»), до этого мы отталкивались от идеи, что генерация ответа занимает на порядок меньше времени чем общение с клиентом. И это отчасти верно. Тем не менее, генерация ответа порою может быть сложной и комплексной задачей, которая может включать в себя чтение и запись на диск, работу с базой данных (которая так же может находиться на удаленном сервере). Что же, получается мы фактически вновь вернулись к исходной проблеме. На практике она разрешается следующим образом: система разбивается на две части — front-end и back-end. Front-end — это сервер, с которым непосредственно общается клиент. Как правило это сервер с асинхронной событийной моделью, который умеет быстро устанавливать связь с клиентами и отдавать им результаты запроса (например, nginx). Back-end — это сервер с блокирующей моделью ввода/вывода (например, Apache), которому front-end делегирует создание ответа для клиента, точно так же как он это делает с подсистемой ввода/вывода. Подобный front-end так же называют «reverse proxy», т. к. по сути это обычный proxy-сервер, но установленный в том же серверном окружении, что и сервер, к которому он перенаправляет запросы.

Если проводить аналогии с реальной жизнью, то front-end — это менеджер с блестящими от белизны зубами и в дорогом костюме, back-end — группа рабочих на заводе, а подсистема ввода/вывода — транспортный отдел компании, на которую работает менеджер и которой принадлежит завод. Клиенты обращаются к менеджеру, отправляя ему письма через транспортный отдел. Менеджер заключает сделку с клиентом на поставку партии изделий и направляет указание рабочим изготовить партию. Сам менеджер, в свою очередь, не ожидает пока рабочие закончат исполнение заказа, а продолжает заниматься своими непосредственными обязанностями — заключает сделки с клиентами и следит за тем, что бы весь процесс происходил согласованно и ладно. Периодически менеджер связывается с рабочими что бы осведомиться о степени готовности заказа, и, если партия готова, то дает указание транспортному отделу отправить заказ клиенту. Ну и, естественно, периодически следит, что бы товар дошел до клиента. Вот так придуманная тысячи лет назад идея разделения труда нашла неожиданное применение в высоких технологиях.

И жнец, и швец, и на дуде игрец (казалось бы, причем тут JavaScript?)


Что же, все это прекрасно работает, но как то наша система чрезвычайно усложнилась, не находите? Да, хоть мы и делегируем генерацию ответа другому серверу, это все равно не самый быстрый процесс, т. к. в ходе него могут происходить блокировки из-за файлового ввода/вывода и работы с базой данных, что неминуемо приводит к простою процессора. Так как же нам вернуть системе целостность и при этом ликвидировать узкие места в процессе генерации ответа? Элементарно, Ватсон — сделаем весь ввод/вывод и работу с базой данных неблокирующими, построенными на событиях (да-да, то самое evented I/O)!

«Но это же меняет всю парадигму создания веб-приложений, и большинство имеющихся framework'ов уже не применимы или применимы, но решения с их использованием не элегантны!» — скажите вы и будете правы. Да, и нельзя исключать человеческий фактор — применяя закон Мерфи можно утверждать, что «если имеется возможность использовать функции блокирующего ввода/вывода, то кто-нибудь рано или поздно это сделает», поломав таким образом всю первоначальную задумку. Это лишь вопрос времени, объемов проекта и квалификации программистов. «Be careful making abstractions. You might have to use them.» (англ. «Будьте осторожны в создании абстракций, ведь, возможно, вам придется их использовать») — говорит Райан в своем выступлении на Google Tech Talk. Так давайте будем придерживаться минимализма и создадим лишь фундамент, который позволит нам разрабатывать веб-приложения и при этом будет настолько хорошо заточен под асинхронную модель программирования, что у нас не будет возможности, а главное — желания, от нее отступить. Так какой же минимум нам нужен?

Очевидно, что для начала нам нужна исполняющая среда, основные требования к которой — быстрое исполнение кода генерации ответа и асинхронный ввод/вывод. Какой современный язык программирования заточен под событийную модель, известен всем веб-разработчикам и при этом имеет быстрые и активно развивающиеся реализации? Ответ очевиден — это JavaScript. Более того у нас в распоряжении есть JavaScript-движок V8 от Google, распространяемый под очень либеральной BSD-лицензией. V8 прекрасен во многих аспектах: во-первых, он использует JIT-компиляцию и множество других приемов оптимизации, а во-вторых, это образец добротно сделанного, продуманного и активно-развивающегося программного продукта (обычно я привожу V8 в качестве примера по-настоящему качественного кода на C++ для коллег на работе). Добавим ко всему этому библиотеку libev, которая позволит нам легко организовать событийный цикл и предоставит более высокоуровневую обертку для механизмов polling'а (так что нам не придется заботиться об особенностях его реализации для различных операционных систем). Так же нам понадобится библиотека libeio для быстрого асинхронного файлового ввода/вывода. Отлично, на этом нашу исполняющую среду можно считать готовой.

И, конечно же, нам нужна стандартная библиотека, которая будет содержать JavaScript-обертки для всех базовых операций ввода/вывода и функций, без которых в веб-разработке далеко не уйдешь (например, парсинг HTTP-заголовков и URL, подсчет хэшей, DNS-резолвинг и т. д.).

Node.js architecture

Наверное, стоит нас поздравить — мы только что придумали концепцию очень быстрого сервера — Node.js.

I'm just sayin'


Резюмируя, хочется сказать, что Node.js – это очень молодой проект, который при правильном использовании может в свое время произвести революцию в мире веб-разработки. Сегодня у проекта есть ряд еще нерешенных проблем, осложняющих его использование в реальных высоконагруженных системах (хотя уже имеются прецеденты). Например, Node.js представляет собой по сути лишь один worker. Если у вас, допустим, двухядерный процессор, то единственный способ по полной использовать его аппаратные ресурсы с Node.js — это запустить два экземпляра сервера (по одному на каждое ядро) и использовать reverse proxy (например, тот же nginx) для балансировки нагрузки между ними.
Но, все подобные проблемы разрешимы и над ними ведется активная работа, а вокруг Node.js уже строится огромное коммьюнити и многие крупные компании уделяют немалое внимание данной разработке. Остается лишь пожелать мистеру Далу довести его дело до конца (в чем, кстати, можно ему помочь), а тебе, дорогой читатель, — провести много приятного времени за разработкой под Node.js.
@inikulin
карма
96,0
рейтинг 0,0
Похожие публикации
Самое читаемое Разработка

Комментарии (252)

  • +37
    Напишите еще статью с примерами разработки на node.js
    • +36
      С радостью! Как раз в планах имеется подобный топик.
      • 0
        ок
        • 0
          Каюсь, забил я на писательство. К сожалению, на него банально не хватает времени.
  • +3
    Так где же тут слабое звено? Их здесь целых два — прием запроса от клиента и отправка ответа.
    Отдаём это на откуп nginx, обрабатывающему все запросы в одном потоке (ну, можно и в нескольких, если хочется все процессы занять) и спим спокойно, продолжая использовать существующую инфраструктуру.
    • +7
      Именно об этом и повествует абзац из которого вы взяли данную цитату
    • +3
      Тьфу, не дочитал.
      Что же, все это прекрасно работает, но как то наша система чрезвычайно усложнилась, не находите? Да, хоть мы и делегируем генерацию ответа другому серверу, это все равно не самый быстрый процесс, т. к. в ходе него могут происходить блокировки из-за файлового ввода/вывода и работы с базой данных, что неминуемо приводит к простою процессора.

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

      Как мне кажется, запихивать всё в одно место — не всегда наилучшее решение, оставьте работу с клиентами HTTP-серверу, а логику обрабатывайте на чём-нибудь, с чем он связывается через fastcgi (через unix-сокеты работает _очень_ быстро). Таким образом ещё и статика будет нормально раздаваться.
      • +3
        Само собой, Node.js — это не silver bullet. Но когда нужна простота инфраструктуры, быстрое развертывание и простая разработка я выступлю за Node.js (как только его доделают конечно же =))
        • +3
          Я сейчас использую связку nginx+mono-fastcgi-server, получил плюшки ASP.MVC на сервере с дебианом, очень доволен. Единственное, mono надо компилять свежий, старьё в репах lenny неработоспособно.
      • +3
        Вы точно уверены что «через unix-сокеты работает _очень_ быстро»? Я пробовал по разному настраивать nginx+php-fpm для отдачи <?php phpinfo(); на разных серверах и в итоге получалось, что только, используя tcp я смог добиться отдачи в 100000 одновременных соединений без единого fail через ab.
  • +7
    Вы уж определитесь, эзотерическая или экзотическая.
    • +3
      Спасибо, пофикшено
  • +8
    > Какой современный язык программирования заточен под событийную модель, известен всем веб-разработчикам и при этом имеет быстрые и активно развивающиеся реализации?
    Если взять первый и последний пункт — то Erlang, только он чуть хуже известен разработчикам.
    Зато событийность, fsm, эффективное использование всех ядер, надежность (чтобы ошибка в одном запросе не уронила все остальные) — все это «из коробки».
    На мой взгляд, имело бы смысл сделать обвязку всего этого добра на эрланге, а контент генерить каким-нибудь скриптовым языком.
    • +4
      Согласен, Erlang, пожалуй, даже лучше подходит для данных целей, но как вы правильно отметили — он меньше знаком разработчикам. Чего нельзя сказать о JS, который известен подавляющему большинству веб-программистов. Из чего вытекают два его неоспоримых плюса: 1)реализации исполняющей среды будут продолжать развиваться и поддерживаться крупными мейнтейнерами (в нашем случае — Google), 2)не потребуется заниматься переобучением персонала
      • +3
        Да. Наличие разработчиков — это очень важный фактор. См. историю успеха PHP.
      • +2
        отмечу что большинству знаком не js, а js фреймворки (jquery, prototype, mootools), основная масса в лучше случае умеет создавать функции для js

        зы в питере сейчас не найти толковых яваскриптеров, есть кадровый «голод»
        • +4
          х3, я наверное исключение, но лично я неплохо пишу на JS, и вообще не знаком с JS фреймворками :D
          • –1
            и вообще не знаком с JS фреймворками :D

            • +1
              А зря.
              • –1
                Почему сразу зря? Каждому свое. Я люблю low-level.
                • +1
                  потому что вы можете любить low-level и даже использовать свой фреймворк/писать без фреймворка. Но не знание общепринятых фреймворков повышает ваш уровень профессионализма. Тем более, что в Javascriptе они прекрасны.
                  • +1
                    Если будет проект с требованием использования фреймворка — я способен быстро освоить нужный.
                    Учить заранее то, что может и не пригодиться — не вижу смысла, у меня есть интересные вещи для изучения и без этого.
                    При разработке «для себя» тянуть за страницами многосоткилобайтовые фреймворки не очень хочется.
                    • +1
                      я знаю на высоком уровне несколько Javascript фреймворков и при этом умею хорошо писать на чистом JS.
                      так вот — мне вас жаль)
                      • +3
                        Если в текущий момент два разрабатываемых мной проекта вообще не требуют JS — мне что, надо все бросить и изучать фреймворки? Зачем?
                        • +2
                          но лично я неплохо пишу на JS, и вообще не знаком с JS фреймворками

                          Неплохо писать на JS и быть незнакомым с фреймворками в большинстве случаев — мазохизм.
                          • –1
                            Это ваше имхо.
                            • –1
                              это недюжинный опыт мой и многих разработчиков, которые знают вариант программирование и без фреймворка и с фреймворком.
                              • 0
                                Ваш и других разработчиков опыт — истина в последней инстанции, лишающая других права иметь свое мнение и предпочтения?
                                • –1
                                  вам нихто не мешает иметь своё сообственное мнение, что вы так нервничаете?
                                  просто чтобы утверждать, что о преимуществах разных подходов — необходимо знать все эти подходы, а не говорить «не пробовал, но осуждаю».
                                  а ваше невежество и отрицание хороших практик может послужить плохую службу тем, кто будет поддерживать ваш код.
                                  вы бы попробовали перед тем, как осуждать и с гордостью говорить о том, что не смогли осилить отличные инструменты.
                                  • +1
                                    А я где то утверждал, что делать так, как делаю я — единственно правильно и хорошо?
                                    Я писал, что так делаю я. Что так нравится мне. Это мое мнение.
                                    Вы же начали как раз таки кидаться фразами «мазохизм» «мне вас жаль» «а зря» и т.п.
                                    Я предлагаю сойтись на мнении, что для каждой задачи нужен подходящий инструмент и что нет абсолютной истины в последней инстанции, все субъективно.
                                    • 0
                                      а я вам могу просто порекомендовать посмотреть фреймворки. без подъёбок — не пожалеете.
                                      • 0
                                        Спасибо за совет, обязательно посмотрю. Просто пока совсем не до того, как уже писал, два проекта, один на C#, другой на C, но если будет задача подходящая — у меня было в планах глянуть jQuery :)
                                        Кстати, гляньте демку, которую я постил чуть ниже, у меня как раз большинство задач было такого рода — где важнее скорость работы и объем, чем скорость разработки, наверное поэтому не возникало желания посмотреть фреймворки.
                      • 0
                        Ваше мышление ограничивается фреймворками. Они являются вашим ограничителем при выборе решений.
                        • 0
                          моё мышление — разносторонее и основанное на опыте программирования без фреймворков и программирования на базе разных фреймворков.
                          • 0
                            Какие основные проблемы большинства популярных фреймворков вы знаете?
                            • –2
                              не надо меня инспектировать, я вам не провинившийся студент.
                              • 0
                                Для человека, который хоть раз в жизни над этим задумывался, дать ответ особого труда не составляет.
                                • 0
                                  я осознаю проблемы большинства фреймворков. именно потому через год опыта работы с JQuery я перешёл на MooTools для некоторых фреймворков.
                                  Более того, я знаю, как эти фреймворки устроены, потому знаю их внутренние недостатки и приблизительно представляю, где могут быть потери производительности.
                                  но я не обязан перед вами отчитыватся, словно вы профессор, а я — школьник.
                                  • 0
                                    Устройство фреймворка не влияет на проблемы. Проблемы лежат за пределами их содержимого. Например, большинство нынешних фреймворков работают по принципу «Сначала найди что-то, а потом работай с этим». Реальность же такова, что в процессе изменения задачи изменяется и содержимое дерева нод, уровни вложенности, структура. И поэтому приходится постоянно видоизменять и HTML, и JS. Это один из примеров проблематики.
                                    • –1
                                      какая проблема? в JQuery есть live и delegate для этого. более того, даже до появления этих методов всё отлично работало через event.target. В фреймворках есть некоторые проблемы, но то, что вы сказали к ним явно не относится.
                                      • –1
                                        Нет проблем, все нормально, не отвлекайтесь.
                        • 0
                          Диагноз по аватарке?
                          В принципе, я понимаю ваш скептицизм, но что, чёрт побери, делать с фактом «фреймворки ускоряют разработку»?
                          • –1
                            Какие из? Я могу сказать, что любая команда разработчиков рано или поздно придет к своему собственному фреймворку. Чужие фреймворки ускоряет начальную разработку, но не длительную поддержку продуктов в актуальном состоянии. Стоимость разработки на собственном фреймворке гораздо дешевле, чем на фреймворках сторонних производителей.
                            • +2
                              глупости.
                              • –2
                                Какой содержательный и конструктивный ответ! Браво!
                            • 0
                              Стоимость разработки на собственном фреймворке гораздо дешевле, чем на фреймворках сторонних производителей.
                              Нет-нет, что вы, это вовсе не синдром NIH.
                              • –1
                                А при чем тут Национальный Институт Здоровья? )
                        • –1
                          фреймворки дополняют функционал, которого не хватает в JS. В HTML5 уже добавлены css expressions, getEleventsByClassName и т.д.
                          • 0
                            Фреймворк, написанный на JS не может дополнять функционал самого JS. Он может предоставлять более быстрый доступ к удобному функционалу. Но этот же функционал можно сделать и без фреймворков.

                            CSS-expressions не дополняют и не расширяют JS, и тем более фреймворки, они затыкают те дыры, которые традиционно приходилось решать при помощи JS.
                            • –1
                              Конечно можно, можно и на ассемблере это сделать… просто будет ещё дольше. Просто фреймворки реализуют функционал, которого не хватает в языке. Потом за ними и стандарты подтягиваются, и браузеры.
                              • 0
                                Любая функция JS реализует функционал, которого нет в JS.

                                Чувствую себя КО
                    • +2
                      Не покажете ваш код?
                      • +1
                        На чистом JS? А зачем?
                        Вы хотите меня ткнуть носом в какую нибудь ошибку или некрасивость и злорадно похихикать? Смысл?
                        • 0
                          Боюсь так и будет.
                          • 0
                            Ссылка ниже) тыкайте
                            • 0
                              Я как раз пролистал :-)
                              • 0
                                Но не считаю себя достаточно сведущим, чтобы оценивать :-)
                          • –3
                            Боюсь, что ваше тыканье может быть осмеяно. Приведенный пример категорически запрещено писать на фреймворках.
                            • –2
                              Дело не в использовании или не использовании фреймворков, а в представленном по ссылке коде.
                              • 0
                                Для начала стоит задуматься, почему там не используются популярные фреймворки.
                                • 0
                                  Если какой-то код упрощён для ускорения в ущерб понятности, он должен быть прокомментирован. Причины должны быть изложены в комментариях. Об остальном сказал TheShock.
                                  • 0
                                    Любые вызовы функций делают свои пенальти. Чем проще код, тем меньше пенальти на обслуживание инфраструктуры вызовов, тем выше производительность.
                      • +1
                        Ок, специально для активно минусующих дам ссылку на сделанную фо фан демку — lorgame.ru/sprites2.php — в самой странице код намеренно был обфусцирован, не помню уж почему) подключаемые скрипты нет.
                        • +3
                          Ну вот просто оцените:
                          var div;
                          div=document.createElement("div");
                          div.id='spritediv'+id;
                          div.style.position='absolute';
                          div.style.overflow='hidden';
                          div.style.left=x-bx;
                          div.style.top=y-by;
                          div.style.width=width;
                          div.style.height=height;
                          document.body.appendChild(div);
                          
                          // =>
                          
                          $('<div/>', { id : 'spritediv' + id})
                          	.css({
                          		position : 'absolute',
                          		overflow : 'hidden',
                          		left     : x-bx,
                          		top      : y-by,
                          		width    : width,
                          		height   : height
                          	})
                          	.appendTo('body');
                          


                          Потом, мне не понравился этот участок. Могу объяснить, почему, но, думаю, вы и сами догадаетесь.:
                          function SAddSprite(name,width,height,bx,by,x,y,sx,sy,tx,ty,dir,states,state)
                          {
                             var len=sprites.length,id=sprcurid++;
                             sprites[len]=new Array();
                             sprites[len][0]=id;
                             sprites[len][1]=name;
                             sprites[len][2]=width;
                             sprites[len][3]=height;
                             sprites[len][4]=bx;
                             sprites[len][5]=by;
                             sprites[len][6]=x;
                             sprites[len][7]=y;
                             sprites[len][8]=sx;
                             sprites[len][9]=sy;
                             sprites[len][10]=tx;
                             sprites[len][11]=ty;
                             sprites[len][12]=dir;
                             sprites[len][13]=state;
                             sprites[len][14]=states[state][0];
                             sprites[len][15]=0;
                             sprites[len][16]=state;
                             sprites[len][17]=states;
                             SCreateImage(id,name,width,height,bx,by,x,y,dir,sprites[len][14]);
                             return id;
                          }
                          


                          Функция SRefreshSprites() напоминает perl. Думаю, значительного улучшения читабельности можно было бы достичь, если в SAddSprite указывать в качестве sprites[len] не массив, а объект с именованными параметрами.
                          Почему вы используете
                          var len=sprites.length;
                          sprites[len]=new Array();
                          // Вместо
                          sprites.push(new Array())
                          

                          Уверены, что это будет быстрее, а не медленнее?

                          Функция SAddSprite(name,width,height,bx,by,x,y,sx,sy,tx,ty,dir,states,state) ужасает даже больше, чем drawImage в canvasApi:
                          Вот вы можете сходу сказать, что значит каждый из примеров?
                          // Plain Javascript
                          ctx.drawImage(img, 30, 30, 45, 60, 15, 15, 15, 20);
                          // VS (LibCanvas)
                          ctx.drawImage({
                          	image : img,
                          	crop  : [30, 30, 45, 60],
                          	draw  : [15, 15, 15, 20]
                          });
                          // VS (LibCanvas)
                          ctx.drawImage({
                          	image : img,
                          	crop  : {
                          		from : [30, 30],
                          		size : [45, 60]
                          	},
                          	draw : {
                          		from : [15, 15],
                          		size : [15, 20]
                          	}
                          })
                          

                          Я вот до сих пор не могу запомнить порядок аргументов в оригинальной функции.

                          И еще. Заметно, что вы не знаете очень многих интересных особенностей Javascript. Рекомендую вам поизучать внутренности и устройство фреймворков — будете приятно удивлены.

                          Не обижайтесь, ничего личного. Вы ведь сами просили прокомментировать.
                          • +1
                            Благодарю за конструктивную критику.
                            Использование объектов возможно, но мне кажется, что массивы быстрее. Писалось конкретно для небольшой демки, поэтому тут нестрашно иметь такие страшные прототипы функций)

                            А вообще да, я бы не осмелился назвать себя профессиональным разработчиком на JS, опыта у меня в нем не просто меньше, а на порядки меньше чем в «основных» для меня языках — C, php. В последнее время работаю также с C#, но там тоже опыта пока не так много.
                            • 0
                              очень спорный вопрос, что быстрее. а главное — имеет ли смысл это ускорение. Видимо, вы на JS стараетесь перенести логику работы на C. На самом деле, если очень увлечся этим языком и разобратся, то вы будете в дичайшем восторге ;)
                              • +1
                                каюсь, я почти везде ее переношу (логику C) :D
                                это моя проблема, да.
                              • +1
                                впрочем я пока не в дичайшем, но в некотором восторге от C#, ввиду его заточенности под _быструю_ разработку и минимизацию ошибок. Писать на нем гуевые приложения — одно удовольствие.
                              • 0
                                А я вот не в востороге от js. Даже скорее меня от него тошнит. Это я к тому, что не обобщайте :)
                            • +3
                              Массивы в JS — те же объекты, по сути ) Не должно там быть заметной разницы в скорости.
                          • 0
                            Производительность приведенного вами кода будет плачевна. Да, быстрее написали, красивее вроде выглядит, но медленнее работает.
                            • +1
                              нормально работает. это не будет узким местом, особенно учитывая тот факт, что функция вызывается крайне редко.
                              более того, многие вещи во фреймворке оптимизированны с учётом особенностей работы языка и в итоге может оказатся, что весь код на чистом ЖС тормозит больше, чем с использованием фреймворка.
                              • +1
                                а еще абстрагированно куча проблем с кроссбраузерностью
                              • –3
                                Вы только что нагородили таких огородов…
                                Фреймворк, написанный при помощи JS не может работать быстрее нативного JS кода. Хоть вы тресните, но быстрее работать не будет.
                                • +3
                                  var divs = document.getElementsByTagName('div');

                                  for (var i = 0; i < divs.length; i++) {
                                    console.log(div.id);
                                  }

                                  медленнее, чем

                                  $('div').each(function() { console.log(this.id) });

                                  Я к тому, что фактор кривых рук тоже не стоит упускать из внимания.
                                  • –4
                                    Бенчмарк в студию!
                                    • +3
                                      А вы сами только спрашиваете и оцениваете результат, как я понял?
                                      • +2
                                        он тут главный, он собирает факты, а потом решает, как со всем этим быть. по крайней мере, он так считает.
                                  • +1
                                    jQuery против нативного JS. 10000 элементов.

                                    33 против 17 в FF 3.6
                                    8 против 8 в Хроме 7
                                    17 против 10 в Опере 10.6

                                    Увы, но JQ не быстрее, как бы вам не хотелось.
                                    • НЛО прилетело и опубликовало эту надпись здесь
                                      • +1
                                        Я вам привел цифры, которые опровергают постулат, что на jQ можно написать код, который будет работать быстрее нативного JS. Ваши придирки к цифрам кроме как придирок я воспринимать не могу.
                                        • 0
                                          Зато на jQuery можно писать код быстрее, чем на нативном JS. Если есть слишком узкие места — их всегда можно перевести на нативный JS для ускорения.
                                          • 0
                                            Первый раз писать — быстрее. Поддерживать и развивать — терпения вам и внимательности.
                                • +4
                                  конечно, на искуственных тестах типа document.getElementById('test') vs $('#test') JQuery проиграет. Но, допустим, как на счёт теста — кроссбраузерно выбрать все элементы с классом «testClass» внутри элементов "<ul>".
                                  На JQuery это будет приблизительно так:
                                  $('ul .testClass')
                                  

                                  допустим, на нашем фреймворке это будет так (для ускорения работы уберем парсер запроса):
                                  dom.tagName('ul').className('testClass')
                                  

                                  Вы уверены, что более нативная реализация без парсера будет быстрее? Учтёте в большинстве современных браузерах метод getElementsByClassName? Или и в ИЕ и в Хроме будете перебирать все элементы? Знаете, что во многих браузерах движок ксс-селекторов есть нативно и вполне возможно, что через селектор будет быстрее, чем через два метода? конечно, на всяких низкоуровневых атомных тестах натив будет быстрее (что не факт).

                                  но фреймворки так заоптимизированны, что кроссбраузерное решение практически невозможно сделать более быстрым, чем в, например, JQuery.
                                  • –5
                                    Патетика чистой воды. JQ имеет обвязку, которая создает деградацию по скорости. Решив задачу методами JQ, но не сделав всю его обвязку, можно получить прирост по скорости.
                                    • 0
                                      Судя по минусующим, тут собрались мегагуру, которые верят в сверх-чудо оптимизации фреймворков… :D
                                      • –1
                                        Исходники jQuery доступны публично, поэтому ничто не мешает ткнуть пальцем в эту самую «Тормозную Обвязку». И утереть нос присутствующим. Иначе ваше утверждение выглядит довольно голословно.
                                        • 0
                                          Оно не может быть голословным. jQuery библиотека, написанная на самом javascript. А это значит, что и без её использования можно всегда как минимум повторить её быстродействие, а то и превзойти его.
                                      • +1
                                        Боюсь всё проще и плачевней. Люди не представляют, как оно работает на более низком уровне, чем js, потому вполне логичные слова, которые как-то даже глупо оспаривать, подвергаются остракизму.
                            • НЛО прилетело и опубликовало эту надпись здесь
                              • 0
                                Нет. Просто одно время оптимизацией скорости пришлось заниматься очень плотно.
                          • +3
                            function SAddSprite(name,width,height,bx,by,x,y,sx,sy,tx,ty,dir,states,state)
                            {


                            Согласен, это чудовищно.

                            К тому же что мешало использовать волшебный массив arguments?

                            Если в функции нужны аргументы со значениями по-умолчанию, если у функции много аргументов, если агрументы можно как-то сгруппировать логически — это явно указывает на то, что функция хочет единственный аргумент, который будет являться объектом.

                            function SAddSprite(params) {

                            }
                          • НЛО прилетело и опубликовало эту надпись здесь
                  • –3
                    Вот вы русский язык не знаете, пишете с ошибками, а другим толкуете о каком-то знании/незнании каких-то-там фреймворков. В чужом глазу…
                    • 0
                      Указывать на орфографические ошибки оппоненту — дурной тон, тем более, что у меня они хоть и проскакивают, но встречаются крайне редко.
                      Я русский язык в школе не учил и считаю, что мой уровень знания иностранного для меня языка достаточно высок.
                      Напишите пару предложений на украинском, посмотрим, какой вы грамотный.
                      • +2
                        Этим комментарием я НЕ хотел сказать: «Вы говно, потому что неграмотно пишете по-русски». Я и сам частенько позволяю себе ошибки/опечатки, дело не в этом.

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

                        (А уровень знания языка у вас, без сомнения, высок даже для коренного жителя России, без сомнения. И это не сарказм.)
                        • 0
                          Спасибо.

                          Ну так о чём речь? Я же не говорю человеку, что не надо программировать на Javascript, раз он не владеет в совершенстве фреймворками. Я утверждаю, что отрицать фреймворки нужно только разобравшись в них. Особенно учитывая высокое качество фреймворков на Джаваскрипт.
                          • 0
                            Речь о «каждый дрочит как он хочет», вы же не на работу его принимаете:)
                          • 0
                            почитал ваш профиль, желание спорить окончательно отпало:)
                            • 0
                              в негативном или позитивном плане?
                              • 0
                                В позитивном, конечно. Куча статей про node.js, полезных статей. Так держать!
                    • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          Эх, как бы хотел писать на фреймворках… Аж слезы из глаз текут… Но к сожалению, на JS я пишу не для десктопа, а для embedded (конкретно — для IPTV-приставок), где зачастую уже почти стандарт де-факто — ядро Линукс + браузер (Опера или какой-нибудь ANT Galio). Производительность у приставки в среднем в несколько десятков раз меньше, чем у десктопа, например на D-Link DIB-120, которую ковыряю сейчас, redraw элемента на экране занимает порядка 200 мс, а reflow — не меньше 500 мс. И все остальное в том же духе.
          В таких условиях большинство тестовых страниц с бенчмарками для проверки работы фреймворков (что jquery, что mootools, о монтруозном prototype я и не говорю) вообще не завершается в обозримое время… Поэтому все ручками, ручками. Учитывая, что на JS надо не просто чего-то делать, а рисовать более-менее полноценный пользовательский интерфейс (не ExtJS, конечно, но все-таки), все становится еще интереснее. :-)
          • 0
            это, наверное, очень интересно, честно.
            и как справляетесь? почему бы не написать топик об этом?
            • +5
              Честно говоря, не уверен, что это было бы интересно массовому хабраюзеру. Да и о чем конкретно писать? JS — он и в Африке JS. Есть API от производителя железа — в браузере несколько дополнительных встроенных объектов, через которые можно управлять оборудованием. Основное время уходит вообще не на кодинг, а именно на обход глюков/особенностей как оборудования, так и встраиваемой реализации браузера. Плюс в том, что не нужно поддерживать тот же IE (поддержка которого как раз и занимает немалую часть во фреймворках): ANT Galio/Fresco работает на движке Firefox, а Опера — она и есть Опера (собственно, она сейчас всех плавно с этого рынка и выдавливает — вполне заслуженно, надо сказать). Так что, например, создавать GUI можно достаточно легко на чистом CSS, т.к. поддерживаются и полупрозрачные png, и всякие :before, :after и не нужно думать о костылях для того же IE6… Короче, разработка идет под конкретный браузер по сути, и не нужно ждать, что окажешься во «враждебной» и незнакомой среде.

              Но на десктопе обычно не нужно задумываться о тех же redraw/reflow, а тут это уже важно, т.к., например, применение к диалоговому окошку класса «hide» внутри которого написано «display: none;» и применение непосредственно стиля «display: none;» — это две большие разницы, т.к. смена класса однозначно вызывает именно reflow и отрабатывается раза в три медленнее, чем изменение одного свойства стиля. С другой стороны, иногда бывает лучше спрятать то же окошко под черной фоновой «заглушкой» и показывать его туда-сюда через изменение z-index'а…
              Вся работа с DOM (особенно изменение) происходит очень медленно, поэтому всякие getElementById практически не используются (максимум — один раз, чтобы получить сам объект), а вся работа — только с объектами. Аналогично innerHTML — быстрее будет создать элементы через createElement/createTextNode, собрать из них что надо и один раз вставить, а чтобы потом менять — лучше лишний раз опять же не дергать DOM, а только заменить текстовое содержимое элемента, а временно ненужный — спрятать.
              Мыши нет, а пульт ДУ генерирует события клавиатуры со специальными кодами клавиш. Нужно постоянно следить за фокусом, за активным элементом и так далее. AJAX в виде XHR по сути не используется (либо вообще запрещен, как, например, в приставках Telsey, либо не работает по причине несовпадения доменов, если страничка грузится не по сети, а из внутреннего флеша приставки), поэтому остается только JSONP. Canvas есть и даже работает, но настолько медленно, что моя попытка сделать какой-нибудь скинсейвер для телевизора — не увенчалась успехом. :-)

              И так далее, и тому подобное. За пределами данной узкой сферы вся эта информация слабо пригодна, разве что иногда бывают некие полезные мелочи, слабо освещенные в интернете — типа, как точно проверить, что подключенный динамически CSS-файл полностью загружен и обработан, или как написать текстовое поле с вводом текста как на мобильниках через кнопки с цифрами и весь сопутствующий функционал…

              Вот такие дела. :-)
              • +1
                Очень интересно.
                Массовому хабраюзеру интересны новинки от Эппл и проблемы в России, но что уж тут поделаешь?
                уверен, если бы написали подробненько, с картинками и нюансами — слушателя нашли бы. я бы с удовольствием почитал.
                • +1
                  1) Ну, помимо прочего, я в свободное от остальных вещей время пытаюсь на этом еще и делать свой маленький бизнес. :-) Решения IPTV от больших вендоров стоят по $100 тыс. за инсталляцию. Я вендор небольшой, а на территории РФ/Украины/Казахстана сейчас много мелких провайдеров, которые вводят IPTV/VOD и которым нужно дешевый и простой способ вывести свой мультикаст на телевизор. В этом направлении и работаю. :-) Рассказывать подробно всю подноготную — это рыть самому себе яму. :-) Так что, если есть конкретные вопросы — пишите лучше в личку/аську/скайп/почту — отвечу лично.

                  2) Ну да, что-то типа фреймворка писал, конечно… Не совсем фреймворка — я не настолько хорошего о себе мнения… Просто для всяких мелких вещей немного расширил прототипы, сделал HAL, чтобы легко было портировать на разные приставки (API доступа к оборудованию у всех же разное) ну и что-то типа мини-GUI-библиотечки с основными элементами типа окон, пунктов меню, кнопок и так далее — оптимизированное для обозначенных целей и чтобы можно было достаточно быстро интерфейс рисовать…
              • 0
                кстати, свой фреймворк для этих дел писали?
    • –1
      не хватает документации просто которая есть на основном сайте… маловато примеров кода, но язык отличный имхо… изучение эрланга перевернуло для меня много в мире программирования…
      вообще я задумываюсь о том как бы запустить внутри эрланга мой любимый (на текущий момент) php и получить все плюшки работы с событиями которые там есть…
      • +1
        > изучение эрланга перевернуло для меня много в мире программирования…
        аналогично, функциональное программирование (и Эрланг в частности) это как поворот сознания на 90° — начинаешь видеть гораздо больше, и старые проблемы тоже видятся шире.
        Но сам язык будет жестковат для написания страничек, ему нужен какой-нибудь очень удобный скриптовой «компаньон»: php, js, особые эстеты вот lua вспоминают :)
        • НЛО прилетело и опубликовало эту надпись здесь
          • +2
            Думаю есть. Взять из каждой системы лучшее.
            Сам подумывал над чем-то подобным, но писать некогда.
            • НЛО прилетело и опубликовало эту надпись здесь
              • 0
                Если на одной машине, то общаться можно через unix domain socket (в просторечьи — pipe), в никсах с ними нормально.

                Я не великий спец по сервисам эрланга :), но каких-то особых проблем возникнуть не должно. Можно через вызов процесса (но тут это будет слишком медленно), пайпы, С-шный код можно скомпилить и вызывать внутри вирт. машины.
                • +3
                  unix domain socket (в просторечьи — pipe)

                  Что-ж вы, голубчик, юникс-сокеты и пайпы путаете?
          • +1
            Угу, и несчастному программеру нужно изучить и Erlang и Node… Ну и вообще не понятно что на эрланг переносит а что на ноде.

            На самом деле в Erlang вполне реально писать веб-приложения. Есть реализация Django шаблонов, есть прекраснейший на мой взгляд вебсервер MochiWeb, есть даже CMS на эрланге Zotonic… Так что есть над чем подумать.
            • НЛО прилетело и опубликовало эту надпись здесь
          • +1
            Так ведь часто объединяют Node.JS + Riak, Node.JS + CouchDB, Node.JS + RabbitMQ.
      • +1
        У эрланга фишка в микропроцессах, которых можно миллионами создавать. А если в каждом из миллиона микропроцессов эрланга запустить интерпретатор PHP — сами понимаете что будет.

        Ну и в эрланге не приветствуется написание модулей на других языках. Там даже драйверы для MySQL и Postgre на самом эрланге написаны
        • 0
          понимаю, но можно запустить 1 процесс который будет держать php процесс который будет выполнять полученный php код (или название пользовательской функции, не важно что он там будет выполнять) (ну или через fcgi — но реализация сложнее) и выплевывать его результат в эрланг. это даст возможность легче «вьехать» в мир эрланга, не лишаясь так сказать привычных удобств…
    • НЛО прилетело и опубликовало эту надпись здесь
      • +1
        Вторая должна быть удобнее.
  • +3
    Что не пост про Node.js, то от «задумки» до «революции»)) Лет 10 назад около 30% веб-серверов работало на этой «революции». Так что это простое эволюционное развитие по спирали. Да сейчас JS более популярен, более развит, больше фреймворков и V8 лучше. Но хоть бы кто-то попробовал проанализировать, почему если JS на серверах не прижился тогда, он должен прижиться сейчас. Что мешало тогда, что изменилось сейчас и т.п.
    • +2
      Извините, я в общем то не в курсе, поэтому не было возможности проанализировать. О каких разработках идет речь? Ну и на вскидку могу вам выдать такой аргумент: 10 лет назад не было эффективных реализаций исполняющей среды и JS был еще довольно молодым языком (как следствие — отсутствие наработанных best practices и толковых специалистов).
      • 0
        Было или не было эффективных реализаций исполняющей среды нам трудно уже проверить. Netscape имел сервер-сайд JS в своих веб-серверах.
        • +2
          это было совсем-совсем не то. никакого non-blocking i/o там не было, документы выводились через document.write(). вообщем, полный отстой :)
    • +2
      Посмотрите доклады Крокфорда про Javascript www.yuiblog.com/crockford/. Во второй главе он достаточно подробно отвечает на ваш вопрос =)
  • +4
    >Если у вас, допустим, двухядерный процессор, то единственный способ по полной использовать его аппаратные ресурсы с Node.js — это запустить два экземпляра сервера (по одному на каждое ядро) и использовать reverse proxy (например, тот же nginx) для балансировки нагрузки между ними.

    Вполне все разруливается через socketpair + child_process.spawn с передачей одного сокета из пары в качестве stdin (лучше, конечно, добавить в node.js fork() — но пока его там нет, вполне себе выход).

    Как то так:

    var socketpair = process.binding('net').socketpair();

    var child = require(«child_process»).spawn(
    process.argv[0],
    [process.argv[1], '-/'],
    undefined,
    [socketpair[1], -1, -1]
    );

    child.stdin = new require('net').Stream(socketpair[0], 'unix');


    Здесь "-/" — служебный аргумент, означающий «работать как child».

    В самом чайлде создаем Stream для stdin, и с ним уже делаем что хотим — например, передаем в качестве аргумента (http.createServer()).listenFd.
    • +1
      Может проще Spark? Запускает сразу нужно кол-во процессов ноды.
      • +1
        Посмотрел, там так же сделано. Не знал о таком, изобрел велосипед. Ну, зато разобрался :)
    • +3
      Я все таки жду fork (т.к. люблю теплые ламповые нативные решения =)), т.к. Райна обещал в скором времени. Но тем не менее, спасибо вам за хинт.
  • +1
    А что будет если «обычное» веб приложение запустить на nginx? Он будет работать как апач генерируя каждую страничку и остальные будут его ждать, никаких плюшек от него получено не будет?
    • НЛО прилетело и опубликовало эту надпись здесь
      • +1
        > единственное немного раздражает вложенные функции — callback в callback в callback'е

        Решил вот так (mootools required, но спокойно без него переписывается). Пример использования — как-то так.

        Этакий немного вывернутый chain of responsibility.
        • +4
          Ох уж это слово-которое-не-произносят-вслух.

          Ссылки:

          1. pastebin.com/twb4Zghs
          2. pastebin.com/DtvHfrhD
      • +4
        callback в callback в callback'е — это известный анти-паттерн JS

        JSDeferred — одно из решений проблемы
        cho45.stfuawsc.com/jsdeferred/doc/intro.en.html
      • 0
        654 request per second.
        Тот же синтетический тест без базы — ~3000 RPM :)
        Без базы медленнее, выходит? ;)
        • 0
          Нет, быстрее.
          • +2
            Адмирал очевидность сообщает, что rpm — это requests per minute и 3000 rpm это 500 requests per second, что меньше, чем 654.

            Генералисимус подсказывает, что чем меньше запросов в секунду обрабатывается, тем медленнее считается сервис.
            • 0
              Судя по цифрам, там везде request per second :-)
            • НЛО прилетело и опубликовало эту надпись здесь
  • +3
    Огромное спасибо автору за статью, хотелось бы еще увидеть примеры работы с node.js
  • +2
    Ваня, респект Марианне за такие красивые картинки!
  • +4
    Plurk (ссылка на него дана в конце статьи, «уже имеются прецеденты») недавно переехал назад на Java NIO — amix.dk/blog/post/19577#Is-node-js-best-for-Comet
  • +3
    Давайте покажу еще один момент который node.js(Twisted,phpDaemon и другие, нужный подчеркнуть) решают более менее походя.

    Вам надо — показать шапку сайта, показать список топиков, показать последние топики, и картинки аватар. С кешированием.
    Как это работает — запрос в кеш -> в бд ->запись в кеш -> отображение -> next
    если каждый пункт занимает секунду — это займет 4 секунды. N чтений из кеша, N запросов в бд и N записей в кеш(образно)

    Подход номер 1 — работать пачкой — мы сделаем 1 запрос в кеш, N запросов в БД и 1 запись в кеш.
    Это, будем считать, займет 3 секунды.
    Первое и последнее — пачкой. Запросы в бд очень сложно правильно «запачковать»

    Теперь давайте скажем что у нас асинхнонный(ивентный) запрос что в кеш, что в бд.
    Если кто не понимает — мы отправляем запрос, говоря что надо сделать при ответе и идем ДАЛЬШЕ.
    Приступая к след пункту.
    В данном случае работает правило крайсерской скорости — все едет со скоростью самого медленного.
    И запрос будет отработан за 1 секунду. В том числе, технически, генерацию разных блоков можно выполнять на разных процах или машинах.
    Ну а если на хвост армаде сядут подлодки — можно отдать клиенту 3 блока из 4х, а последний дотянуть в клиент уже после загрузки( чисто технически — влет )

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

    И из «ничего» ускоряем генерацию во столько раз, насколько блоков( узлов, в общем ранг ноды дерева ) мы раздербанили генерацию кода.
    +малек доп расходов и идеалогическое требование к железу дать возможность выдержать паралельные запросы — ведь если у вашей БД только один проц, а к ней приходят запросы не последовательно а, прям таки, обновременно — она обидиться.

    Все это также делается и без разных демонических нод, как говориться — кому как нравиться(правда два года назад я описал свои мысли малек более сумбурно)
  • +3
    Асинхронность есть и в других ЯП — EventMachine для Ruby и Twisted для Python. Так что основной фишкой node.js всё так же и остаётся лишь программирование на JS.
    • +2
      Основной фишкой node.js является отсутствие возможности писать код с синхронным вводом/выводом, причем писать на языке знакомом и PHP, и Python, и Ruby, и ASP и вообще любому веб-разработчику.
      • 0
        Ну опять же, плюсы в том, что это JS — lingua franca Веба. Хотя можно заметить, что JS — довольно жестокий язык и лучше его украсить хотя бы синтаксисом Coffeescript.
        • +1
          да, но мне кажется, что большая часть разработчиков программирует на JS, как на паскале (без прототипов, коллбэков и т.д.). Мало кто действительно умеет писать умный JS
          • +1
            Да, есть такое :). Плюс люди программирую на JS не потому, что любят этот язык, а потому что ничего другое в браузере не работает. После Ruby немного злишься на странности перекосы JS (хотя бы отсутствие foreach, нормального, быстрого, без-лишнего-кода-для-IE ).
            • +1
              ну, на основе JS есть и экзотические варианты — вроде ru.wikipedia.org/wiki/Objective-J :)

              фанатам Objective-C должно нравится.

              вообще жаль, что cappuccino.org/ была куплена Моторолой, а не Эппл. По-моему, очень хороший проект

              (но я сваливаюсь в оффтопик)
              • 0
                В Ruby и Python мире Coffeescript более популярен.
                • 0
                  Парсер — лох, вот нормальная ссылка: bit.ly/6h5JKO
    • НЛО прилетело и опубликовало эту надпись здесь
      • +1
        Ну да, опять же JS. V8 — отличный интерпретатор, я слышал он работает в 3 раза быстрее Python. Но потребление ресурсов не отличается на порядок:
        1. Интерпретатор Руби и Питона кушают больше, но основная потеря — это данные, так что дополнительные 10 МБ не масштабируются при росте данных.
        2. Скорость вычислений в JS больше, но мы все знаем, что основное время в вебе мы просто ждём данных от базы, поэтому, например, применение более быстрой [чем JS] Java не даст существенного роста производительности.
      • +1
        Хотя да, я согласен, что V8 — отличная ВМ, мой комментарий был больше посвящён тому, что async — это не фишка node.js — async есть уже практически в любой быстро развивающейся платформе. И разница между async на разных платформах упирается чисто с разницу между ЯП и качеством ВМ.
        • +1
          async есть в платформах которым уже 10 лет, вот например ASP.NET…
          • +1
            Можно более подробно. Я понимаю, что async можно сделать руками на любой платформе, но интересно, зачем идея неблокирующего API была нужна 10 лет назад и как она реализовалась средствами первых C#, где нельзя было коротко объявить callback (максимум — создавать анонимный класс, реализующий какой-то интерфейс).
            • 0
              IHttpAsyncHandler — это асинхронная работа с HTTP запросами. Весь BCL содержит асинхронные, неблочащие методы Begin/End XXXX для IO, доступа к базам данных, короч для всего. Для сгенеренного юзерского кода (например веб сервисы) тоже есть асинхронные пары. Можно почитать больше про IAsyncResult.

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

              Ну а на текущий момент в C# появилось ключевое слово async. Там уже можно писать аинхронный, неблочащий код ввиде нормального синхронного кода. Без всяких уродских колбеков. ( неплохое описание blog.functionalfun.net/2010/10/c-50-asynchronous-revolution.html ).
              • 0
                Неплохо. Но справедливости ради, скажу, что в Ruby это тоже есть, при этом без всякой модификации языка — гибкости стандартного Ruby 1.9 более чем достаточно, чтобы реализовать аналог await: https://github.com/brainopia/em-easy
                • 0
                • 0
                  Я знаю про раби. Но мы же щас про ASP.NET говорим. Если уже прескакивать на другие языки то стоит упомянуть F#. Там такой код изначально можно было делать средствами языка (Async Workflow — это обычный computation expression). Вопрос наверное больше в фреймворке, а не языке. Правда же класно что обычном .NET async/non blocking API реализовано уже 10 лет?
                  • 0
                    Да, это было весьма дальновидно.
                  • 0
                    Правда, как я понял, разговор идёт не о async работе с клиентами (выдачи им содержимого веб-сайте), а асинхронных запросах контента другого сайта и работы с БД. То есть, веб-сервер всё равно запускался с несколькими worker’ами, обслуживающих пользователей, без единного цикла и т. д.
                    • 0
                      IHttpAsyncHandler — асинхронная работа с клиентами. Тока там не единый цикла, а пул потоков. Но каждый из этих потоков обслуживает скока получится хендлеров. Ведб как тока управление ушло например в ожидане БД, то поток освободился.

                      А вот уже IAsyncResult это аинхронный, неблочащий АПИ ко всему.

                      Единый цикл реализован не в ASP.NET, а в IIS(точнее даже в HttpSys). Там происходит диспечеризация ШТТП запросов, которые потом передаются в ASP.NET (упрощенно, понятно что есть запросы который передаются в другие места).
                • 0
                  Ну, видимо, это особенность языка. Впрочем, очень удобная.
                  В C#, действительно, в самом языке соответствующих конструкций пока нет, но вот будут эти самые «async» и «await», что только еще упростит разработку асинхронных решений, посмотрим там что да как.
            • +1
              Ну, может 10 лет назад, конечно, ничего там не было, однако, для веба, начиная с самой первой версии фреймворка в сборке Web был IHttpAsyncHandler (который, кстати, в более современном виде используется и для реализации асинхронной обработки в ASP.NET MVC), использующий модель мультипоточности для разделения собственно обработки и ввода вывода.

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

              Ну, разумеется, есть и примеры реализаций Reverse Proxy.

              Тем не менее, Microsoft только вот-вот представила Visual Studio Async CTP, который предполагает упрощенную работу с асинхронностью в VS, в том числе с помощью самого языка (C# 5 предполагается сделать с «асинхронными» возможностями out-of-the-box).

              Асинхронность в .NET, как и на любой платформе активно популяризуется, как очень мощный инструмент оптимизации нагрузки, так что появление еще более продвинутых инструментов для асинхронной обработки на .NET — лишь вопрос времени.
              • 0
                Не успели, выше уже написали :). Заодно я там ответил (в рамках разогрева холивара :) ), что в Ruby не надо вводить новую версию языка, чтобы добавить await :). github.com/brainopia/em-easy
                • +1
                  Ruby хорош, что уж там :)
                  • +1
                    +1. Правда хотелось бы уточнить что хорош, для своих применений. Ненавижу писать комплексную бизнеслогику на динамических языках ;).
                    • 0
                      Ну для меня это как раз просто красивый, немногословный (что особенно круто) динамический язык. Я прекрасно понимаю его прелесть и почему рубисты так его любят. Позволяет быстро добиться определенного результата, без особых заморочек с низкоуровневыми штуками. На мой взгляд, идеальный язык для веба и фишек с достаточно простой и понятной логикой. Но больше всего нравится подход комьюнити этого языка, тут и подход к тестированию, и, особенно, принцип Convention over Configuration.

                      Однако, это только одна сторона, и тут уже дело вкуса. Я сам все же больше любитель языков со строгой типизацией, и предпочитаю C#. Для реализации комплексной логики, однозначно, предпочту C#.

                      Вообще, используя тот же ASP.NET MVC, со своей надстройкой в виде соглашений, упрощений, Fluent Builder-ов и прочим, я стараюсь взять лучшее из двух миров. Использовать концепцию простоты, заложенной RoR, но при этом не пытаясь сделать RoR из ASP.NET MVC, а по-максимуму использовать мощь C# и его строгой типизации (Hello Thunderdome Principle).
                    • 0
                      В вашей ситуации мне больше нравится подход JRuby/IronRuby — простое и лёгкое (автоматические тесты, front-end, простую логику) пишем на Ruby, а более низкоуровневые задачи — на Java/C#. При этом классы из Ruby можно использовать в Java/C# и наоборот. В общем очень тесная и довольно надёжная интеграция. Для автоматических тестов — точно must have с RSpec :).
                      • +1
                        Я пробовал. Фигня получается. Все на С# получается значительно быстрее писать.
                • +2
                  Это не то, более слабое средство. Только что посмотрел, что такое em-easy и оказалось, что это просто фьючерсы, а async/await в C# — монада, средство комбинировать асинхронные задачи.
                  • 0
                    Можно подробнее. Я наверное не полностью понимаю смысл слова «комбинировать задачи», как это конкретно выглядит и что даёт.
                    • +1
                      www.intuit.ru/department/pl/funcprog/30/ тут гляньте видео.
                      • 0
                        Я думаю непонимание в терминах ещё осталось. В этой лекции говорится о Async Workflow, когда мы можем создать несколько задач и сказать выполни их все параллельно. Но в README к em-easy именно этот пример и стоит.

                        1. Мы создаём несколько асинхронных задач:
                        requests = Array.new(10) { EM::HttpRequest.new("http://www.postrank.com").get }

                        2. Они уже начинают выполнятся параллельно. Так что, мы пока можем объявить ещё несколько задач.
                        3. Когда нам нужно, чтобы наши асинхронные задачи уже выполнились, мы пишем
                        results = requests.map {|it| wait it }
                        и используем их результат.
                    • 0
                      У объекта представляющую асинхронную задачу есть метод, который принимает на вход функцию. Смысл этого этого метода — как только асинхронное вычисление закончиться применить к результату данную функцию; понятно, что вызов этого метода неблокирующий, а возвращает он объект представляющий новую асинхронную задачу, комбинацию старой и новой.

                      Оператор await берет весь код, который следует за ним (переписывает весь код метода) и передает его как функцию в тот метод аргумента await. Таким образом порождается новая асинхронная задача. Как-то так.

                      P.S. Я об этом уже писал на хабре habrahabr.ru/blogs/net/107498/
                      • 0
                        Так wait в em-easy делает примерно тоже самое. Весь код, который идёт после него, выполнится только тогда, когда асинхронная задача (переданная методуwait) выполнится.
                        Асинхронные задачи создаются в примере командой EM::HttpRequest.new("http://www.postrank.com").get.
                        • 0
                          Да, но в момент, когда происходит вызов wait поток выполнения блокируется, в случае await создается новая асинхронная задача и выполнение не блокируется, а результатом await является задача. await это монада, она позволяет комбинировать и создавать новые асинхронные задачи.

                          Пример, пусть есть два метода f() и g(), которые работают асинхронно и возвращают числа, задача создать новый метод h(), который работает асинхронно и складывает результаты вычислений f() и g(), вот решение на C#:

                          async Task<int> h()
                          {
                            var x = f();
                            var y = g();
                            return (await x) + (await y);
                          }


                          Повторяю вызов h() запустит вычисление асинхронно и тут же вернет управление.

                          Как такое выразить в Ruby?

                          Если нам уже нужен сам результат, то у объекта типа Task обратимся к свойству Result, это эквивалентно wait в ruby.
                          • 0
                            Зачем тогда писать await? Почему нельзя написать в Ruby так:
                            def h
                              x = f()
                              y = g()
                              x + y
                            end
                            
                            result = wait h()
                            

                            Методы f и g возвращают объект запроса (а не результат), его мы и возвращаем обратно.

                            Если Вы говорите о том, как из синхронного метода создать асинхронный (например, f() и g() не написаны асинхронно, а блокируют работу, пока не возвратят результат), то тогда создаём асинхронную обёртку с помощью:
                            def h
                              x = EM.defer { f() }
                              y = EM.defer { g() }
                              x + y
                            end
                            
                            result = wait h()
                            
                            • 0
                              Нет, я написал по комбинацию асинхронных методов (метод асинхронный, если он возвращает не результат, а фьючерс).

                              Писать await нужно, чтобы показать компилятору, где применять магию=)

                              Фьючерсами описать комбинацию асинхронных методов в асинхронный метод нельзя, поэтому то, что реализовано в ruby не аналогично тому, что будет в C# и есть в F#, Nemerle, Haskell.
                              • 0
                                Эм, а в чём разница между моим первым примером и вторым? Может быть, если Вы приведёте более жизненный пример, то я смогу лучше понять.
                                • 0
                                  Так, первый пример это работающий код на Ruby или превдокод?
                                  • 0
                                    В принципе работающий, только + к задаче нельзя применять и в wait пока не добавили обход массива :).
                                    Ниже код должен работать.
                                    def h
                                      x = f()
                                      y = g()
                                      [x, y]
                                    end
                                    
                                    result = h().map { |i| wait i }.sum
                                    
                                    • 0
                                      h() вернёт результат сразу же, не дожидаясь окончания f и g. Код после result = будет выполнен после окончания f и g (ну типа «виртуальный callback», только там на самом деле меньше магии, за счёт использования фиберов).
                                      • 0
                                        Так логика должна быть внутри h, при этом h должна оставаться асинхронной.
                                    • 0
                                      Хе, так это совсем другое. Ладно, формулировка близкая к реальности: есть асинхронный метод GetXml(url) и синхронный метод ApplyXslt(xml,xslt) нужно создать асинхронный метод, который скачивает xml, xslt и применяет преобразование. Требуется, чтобы этот метод был асинхронным и возвращал фьючерс.

                                      Вот решение этой задачи на C#:

                                      async Task<Xml> ApplyRemoteXslt(string xmlUri, string xsltUri)
                                      {
                                        var xml = GetXml(xmlUri);
                                        var xslt = GetXml(xsltUri);
                                        return ApplyXslt(await xml, await xslt);
                                      }


                                      Как решить эту задачу с помощью em-easy?
                                      • 0
                                        «Требуется, чтобы этот метод был асинхронным и возвращал фьючерс» — вот именно это требование можно описать более жизненно, без применения терминов какой-то технологии.
                                        • 0
                                          Я даже не знаю, что ответить. Представьте язык, в котором нельзя объявлять функции самому, а можно использовать только те, что есть в стандартной библиотеке. В принципе, можно писать и на таком языке, но это не удобно. С асинхронными функциями тоже самое, нужно уметь определять свои асинхронные функции. Самый простой способ это сделать — через комбинацию других асинхронных функций.
                                          • 0
                                            Просто, если бы Вы могли сказать конкретную задачу, то я бы мог попытаться сделать аналог на em-easy. Ну вот, например, как дальше будут использовать ApplyRemoteXslt()?
    • +3
      Большинство библиотек для Питона/Руби всё равно синхронны и с этими фреймворками сопрягаются со скрипом.
      • +1
        Вы правы, но для JS большинство server-side библиотек всё равно надо ещё писать. Точно так же для EM многое уже во всю пишут. Так что ситуация паритетная.
    • 0
      В Python есть еще Tornado, который из FriendFeed вынули %)
      • 0
        А Twisted это async? А-то я мог перепутать название, знаю только, что в Python тоже есть что-то подобное.
  • +1
    Сыроват, но перспективы наверняка есть :) Еще + то что клиентская и серверная стороны будут на одном языке…
  • +6
    Критикую.

    1. Абсолютно не раскрыта тема преимущества асинхронного программирования на JS перед любым другим языком.

    2. Стыдливо не говорится через какое место работает асинхронный дисковый IO (hint: через pthreads + нотификация через пайп). При нагрузках от 1.5k запросов в секунду это АД и погибель. Проверено лично на FreeBSD еще несколько лет назад. Ожидать изменений в лучшую сторону как минимум наивно. В обычной ситуации оверхед для такой «асинхронности» значительно превышает время на выполнение самой операции дискового IO. Я уже молчу о том, что подобные трюки фактически превращают наш асинхронный сервер в ту же самую модель с N worker threads

    3. Не раскрыта тема асинхронной работы с СУБД. В частности, для MySQL принципиально отсутствует асинхронный интерфейс и единственный (помимо достаточно грязных, но удивительно эффективных хаков) способ сделать его «асинхронным» — это опять таки N database worker threads со всеми вытекающими оверхедами.
    • –1
      Зачем в асинхронном мире использовать синхронную mysql?
      Есть асинхронная mongodb, пусть она справляется с диском.
      • +4
        Возможно потому, что даже экспериментальному асинхронному миру бывают нужны данные, хранящиеся в проверенном временем бакенде. Не говоря уже о том, что NoSQL применим, мягко говоря, не везде.
        • НЛО прилетело и опубликовало эту надпись здесь
          • 0
            Я в курсе, просто под «вебом» часто понимается связка LAMP, а ее-то хотят превратить в LN?J (Linux-Node.js-?-Javascript). Очевидно, что у клиентских библиотек MySQL есть определенные проблемы, которые мешают поставить «M» на место вопросительного знака.

            У постгри тоже есть ряд проблем, главная из которых «PostgreSQL надо уметь готовить».
    • +1
      В веб-бэкендах довольно редко файловый IO используется. Обычно для этого фронтенд типа Nginx используют.
      С остальными замечаниями согласен.
    • +3
      Будем надеяться, что Drizzle скоро будет готов к продакшену.
    • +1
      3. Нет никаких проблем в реализации асинхронного драйвера для MySQL. Хоть на самом node.js, хоть на C/C++ плагином к оному. Вот, например: habrahabr.ru/blogs/webdev/102167

      Да и без node.js все есть. Например, для приложений на C, использующих libevent: libmca.anight.org

      А асинхронный файловый i/o в общем случае вообще не реализуем :( Посмотрите, через какие ужасные хаки оно сделано в nginx: sysoev.ru/nginx/docs/http/ngx_http_core_module.html#aio
      • +3
        Вот, например: habrahabr.ru/blogs/webdev/102167

        N рабочих тредов + нотификация о завершении по пайпу. Спасибо, такая «асинхронность» успешно загибается на отметке 1.5к запросов в секунду, будучи реализованной нативно на языке C. Просто от обилия системных вызовов, вызывающих переключения контекста.
        Например, для приложений на C, использующих libevent: libmca.anight.org

        В этом случае я предпочту thread pool, хотя бы потому что он будет использовать официальную клиентскую библиотеку. Безусловно, я не верю, что в ближайшем обозримом будущем протокол обмена данными с сервером mysql поменяется, однако использовать поделку без даже самой примитивной документации я не буду. Просто потому что качество заведомо «не на уровне». Это, кстати, без учета того, что наверняка пару десятков функций придется дописывать самому, потому что автору они были не нужны.
        А асинхронный файловый i/o в общем случае вообще не реализуем :( Посмотрите, через какие ужасные хаки оно сделано в nginx

        Это не хаки, а локальная кривизна файлового AIO. Как видно, AIO в линуксе самое кривое (даже glibc использует thread pool в своей реализации асинхронного IO). Собственно, такой сырости и кривизне есть вполне разумное объеяснение: в подавляющем большинстве случаев накладные расходы на асинхронность многократно превышают возможный выигрыш от ее использования.
        • +1
          > N рабочих тредов + нотификация о завершении по пайпу

          Уууупс, извиняюсь — попутал, не посмотрел, куда ссылку дал. Была реализация безо всяких тредов, обычный event loop, что-то сходу не найду (я сам с node.js mongodb использую, так что mysql-либы смотрел только ради интереса). Ну, впрочем, это ничего не отличается от libmca по сути.

          Официальных асинхронных клиентских библиотек мы вряд ли дождемся (если только drizzle, у которого протокол совместимый). Приходится пользоваться «наколеночными поделками» — шашечек нет, да, зато работают.

          С мемкешом и mongodb у меня 6k rps вполне держит, мне этого с запасом :)
        • 0
          >> Собственно, такой сырости и кривизне есть вполне разумное объеяснение: в подавляющем большинстве случаев накладные расходы на асинхронность многократно превышают возможный выигрыш от ее использования.

          В случае disk i/o — в целом согласен, хотя есть и меньшинство. Конечно, основное преимущество асинхронка дает при работе с сокетами (с чем, собственно, и проблем нет).
    • +1
      Асинхронный файловый ввод/вывод действительно использует все тот же thread pool. Но стоит отметить, что файловый ввод/вывод на стороне сервера операция редкая. А вероятность того, что несколько запросов будут одновременно выполнять данную операцию — так же невелика при правильном дизайне. С MySQL действительно имеются проблемы, которые иногда могут быть решены (например, введением memcached прослойки или вообще отказом от MySQL). Как я уже говорил Node.js — не silver bullet. В этом мире не бывает идеальных вещей, способных разом разрешить все проблемы. Программное обеспечение — совершенно не исключение из этого правила.
    • 0
      как нет если есть асинхронные драйвера к MySQL.
  • +4
    Рискую огрести, но все же замечу…

    Только мне кажется что все рассказы о перспективности NodeJS слишком раздуты? Просто асинхронный подход в программировании известен давно. Асинхронный IO так или иначе поддерживается всеми современными ЯП, для многих есть довольно мощные асинхронные фреймворки.

    Говорят что у JS нет старого наследия в виде кучи синхронных библиотек… При этом для Node до сих пор нет надежного по настоящему асинхронного драйвера для того же мускуля.

    Да и в чем преимущество Node помимо быстрого v8? В чем преимущество JS помимо того что его «знает» любой уважающий себя веб-разработчик (причем большинству придется очень мучительно переучиваться, чтобы написать на Node нормальное, правильное приложение)?
    • +3
      Кстати, у Вконтакте на ноде написан Jabber сервер и они ругались что он у них течет и плохо работает с SSL www.insight-it.ru/masshtabiruemost/arkhitektura-vkontakte/
      • +2
        Кстати, они используют в нём MySQL и не особо жалуются.
        • +2
          Они то не жалуются, а вот те кто пытался пользоваться… Если их сервер работает, что бывает не часто, то он притормаживает, уж не знаю с чем это связано, но факт :)
          • +1
            Ну не знаю, я пользуюсь их Жаббером и особых тормозов не замечал.
    • +3
      Асинхронного драйвера не будет, пока сама MySQL не будет этого позволять. Нода тут не причем.

      Насчет преимуществ. Eсть возможность перенести библиотеки с клиента на сервер. Рисовать на canvas'e и отдавать их клиенту в виде png. Использовать jQuery, в качестве шаблонизатора, добавляя и изменяя узлы дерева html, который еще будет отдан клиенту.

      JS достаточно удобно сконструирован, чтобы поддерживать асинхронный режим — анонимные функции, замыкания и т.п.
      • 0
        Не исключено что я чего то недопонимаю, но ведь общение клиента и сервера MySQL происходит через сокеты? Соответственно как ты клиентский драйвер напишешь так он и будет с MySQL общаться. Напишешь драйвер с асинхронным сокетом — будет асинхронно, напишешь синхронный драйвер — будет синхронно…

        На примере WEB: ведь если на стороне WEB сервера стоит синхронный апач это не значит что я не могу написать для него асинхронного WEB клиента?

        Мне почему то кажется, что просто не осилили пока еще написать свою собственную реализацию драйвера MySQL на асинхронных сокетах…

        Или я что-то недопонял?
        • 0
          Если сервер работает по принципу: «получил запрос → обработал → послал ответ», то могут быть проблемы: нужно всегда быть готовым к приему ответа, т. е. держать дополнительную нить для этого. Сервер должен уметь отвечать на вопрос «готов ли результат запроса?» или иным способом оповещать клиентскую библиотеку, и отдельно обрабатывать фазу отправки результата.
          • +2
            В плане невозможности нативного асинхронного моста для MySQL вы правы. Но, не всё так плохо. Если приложение использует MySQL не очень активно, то лишний процесс с очередью запросов в БД ничем не помешает.
            • 0
              Ну, собственно, такие костыли обычно и городят: десяток-другой рабочих потоков, разгребающие очередь запросов. Работает достаточно отвратительно из-за накладных расходов на синхронизацию.
          • 0
            ну все равно не понял… Простейший пример. Как Я СЕБЕ представляю работу драйвера MySQL:

            * создается сокет — соединение клиента с сервером. Клиентский драйвер делает сокет асинхронным, добавляет его в event loop
            * клиент составляет SQL запрос скармливает его драйверу, драйвер преобразует его в двоичный mysql протокол и пишет в сокет MySQL соединения (асинхронно), входит в select() или epool() kqueue() запрос event loop'a и ждет ответа MySQL с данными или ошибкой (или каких то других сокетов)
            * mysql сервер в это время считывает запрос от клиентского драйвера (синхронно) обрабатывает его, генерирует бинарный ответ и пишет его «обратно в сокет» (синхронно)
            * клиентский select/epool/kqueue обнаружил входящие данные от MySQL, разблокировался и начал считывать (асинхронно) ответ MySQL, передавать его драйверу на распаковку бинарных данных.
            * все данные считаны и распакованы, клиентский драйвер вызывает Callback с полученными данными.

            Не вижу при такой реализации никаких препятствий в реализации асинхронного драйвера. Или все же я что то не учел или не понял?
            • 0
              Драйвер не должен держать своего event loop или предполагать наличие существующего. Он должен уметь посылать запрос, проверять статус запроса (готов/не готов) и получать ответ. Огромным плюсом была бы возможность получения от драйвера файлового pollable дескриптора, событие чтение на котором бы означало «результат готов».

              Для подобных трюков libmysqlclient абсолютно непригоден.
              • 0
                Конечно, это было бы удобно, но приходится работать с тем, что есть.
                В конце концов, не стоит надеяться, что MySQL/Postgres/etc. перепишут с тредовой модели на event-loop. Так что степень костыльности не изменится, если костыли переместятся из кода биндинга/нативного javascript кода в некую внешнюю libmysqlasync.
                • +1
                  СУБД занимаются не только сетевым вводом-выводом. Они очень много времени проводят в вычислениях. Мультиплексирование в явном виде там не применимо, разве что в потоке ввода-вывода, отвечающем за общение между клиентскими приложениями и рабочими нитями. Но применение такой модели не очень оправдано.
                  • +1
                    О чём и речь. Так что я не вижу ничего страшного в том, чтобы реализовывать встраивание запросов к MySQL в event loop так, как это делают сейчас.
              • 0
                А разве потом этот pollable дескриптор не добавляется в общий Event loop? Почему нельзя в качестве pollable дескриптора использовать сам сокет соединения куда мускуль будет писать ответ?
            • +1
              Такой драйвер уже есть, и не один. Однако многие считают это костылём :-)
        • +2
          При соединении с MYSQL создается сессия (@-переменные, значения автоинкрементных ключей). Далее клиент работает с этой сессией в синхронном режиме. Он не может послать след. запрос, пока не получит все данные из первого (<-- вот тут косяк).

          Создание нового соединения на каждый запрос слишком накладно.
          • 0
            о… понял. Спасибо!

            Ну, пулл коннектов к MySQL пошире и в путь)) Не обязательно же все запросы по одному соединению гонять.
            • 0
              Сейчас драйверы в ноде так и работают.
          • 0
            Общение с практически любым TCP-сервером выглядит примерно так же. И решения одинаковые — отдельные соединения либо очередь.
          • +1
            На самом деле, достаточно было бы не блокироваться в ожидании ответа от сервера.
      • +1
        Анонимные классы и полноценные замыкания есть в Java с версии… Не знаю точно, с какой, но в 1.3 они уже были. Возникает вопрос: чем настоящая энтерпрайзная джава хуже?

        Я считаю, многие люди наивно надеятся сэкономить на найме разработчиков для клиентской и серверной части: взять одного человека и нехай он jQuery с Node.js запрягает, ведь у него же в резюме «Java script» написано! Думаю, всем понятно, почему этим наивным мечтам не суждено сбыться.
  • 0
    Я все жду появления сервера на нод.жс для пхп. Если слабое звено это I/O система, то пхп как ничто другое подходит для написания страничек :)
    Хотя, думаю, не трудно сделать подобное самому :)
    • 0
      Зачем?
      • 0
        Ну хотя бы для того чтобы компенсировать синхронный апач
        • 0
          Nginx с этой задачей получше должен справляться…
        • 0
          Синхронность PHP всё сведёт на нуль :-)
    • 0
      Самое слабое место для асинхронного программирования — это мозги разработчика. Писать асинхронно как минимум непривычно, почти всегда многословно и зачастую недостаточно непрямолинейно и неочевидно.

      А уж какую выгоду вы ожидаете от использования PHP с его синхронными библиотеками в асинхронном сервере мне вообще непонятно.
      • 0
        Да уже понял, спасибо :)
  • 0
    inikulin, а под какой иллюстрации картинки нарисованы? :-)
    • +1
      Извините, но боюсь я не понял сути вашего вопроса =)
      • 0
        Бред написал :-D Исправил не то слово.

        Под какой лицензией иллюстрации нарисованы? :-) Можно ли их использовать и на кого ссылаться.
        • +1
          Используйте на здоровье. По поводу ссылки — достаточно «спасибо» моей любимой девушке Марианне, которая оказала огромную помощь при создании этих картинок. Ей будет очень приятно =)
          • 0
            Передайте Марианне спасибо от меня, они «очень».
  • +4
    Прямо экстаз испытал при прочтении статьи. Это не просто восхитительно, это действительно достойно занесения в избранное. Браво!
  • +5
    Очень крутая статья, стиль повествования — супер, пишите больше и чаще, читается взахлеб :)
    • +2
      Однозначно согласен. Можно хорошо разбираться в технологиях, а можно хорошо уметь излагать свои мысли. Сразу две эти вещи в одном человеке встречаются довольно редко. Автор — молодец, большое ему спасибо за статью. :)
  • +2
    В качестве reverse and caching proxy попробуйте www.varnish-cache.org/ от разработчика ядра FreeBSD. Поверьте оно того стоит. У хорошего друга падение нагрузки от 15% до 40% на достаточно нагруженых сайтах.
  • +1
    Отличная статья, получил огромное удовольствие! Кратко и доходчиво вы рассказали обо всем полезном, что было на highload в этом году. Спасибо!
  • 0
    Я недавно начал писать под Node.JS, и он у меня вызвал смешанное ощущение. С одной стороны, все просто и красиво. С другой, без дополнительных модулей не хватает функционала. Но в целом впечатления хорошие.

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.