Что такое ответ Haskell на Node.js?

Я считаю, что сообщество Erlang не завидует Node.js, поскольку оно неблокирует ввод-вывод изначально и имеет способы легко масштабировать развертывания для нескольких процессоров (что-то даже не встроено в Node.js). Подробнее см. http://journal.dedasys.com/2010/04/29/erlang-vs-node-js и Node.js или Erlang

Как насчет Хаскелла? Может ли Haskell предоставить некоторые из преимуществ Node.js, а именно, чистого решения, чтобы избежать блокировки ввода-вывода, не прибегая к многопоточному программированию?


Есть много вещей, которые привлекательны с помощью Node.js

  • События: нет манипуляций с потоками, программист предоставляет только обратные вызовы (как в фреймворке Snap)
  • Гарантируется, что обратные вызовы будут выполняться в одном потоке: нет условий гонки.
  • Хороший и простой UNIX-API. Бонус: отличная поддержка HTTP. Также доступен DNS.
  • Каждый ввод-вывод по умолчанию является асинхронным. Это позволяет избежать блокировок. Однако слишком большая обработка ЦП в обратном вызове будет влиять на другие соединения (в этом случае задача должна разделиться на более мелкие подзадачи и перепланировать).
  • Одинаковый язык для клиентской и серверной сторон. (Я не вижу слишком большого значения в этом, однако jQuery и Node.js используют модель программирования событий, но все остальное совсем другое. Я просто не вижу, как код обмена между серверной и клиент- сторона может быть полезна на практике.)
  • Все это упаковано в один продукт.

Ответ 1

Хорошо, так что немного посмотрев node.js-презентацию, на что я указал @gawi, я могу сказать немного больше о том, как Haskell сравнивается с node.js. В презентации Райан описывает некоторые преимущества Green Threads, но затем продолжает утверждать, что он не считает недостаток абстракции нитей в качестве недостатка. Я бы не согласился с его положением, особенно в контексте Haskell: я думаю, что абстракции, которые предоставляют потоки, необходимы для того, чтобы сделать код сервера более понятным и более надежным. В частности:

  • Используя один поток для каждого соединения, вы можете писать код, который выражает связь с одним клиентом, а не писать код, который одновременно работает со всеми клиентами. Подумайте об этом так: сервер, который обрабатывает несколько клиентов с потоками, выглядит почти так же, как тот, который обрабатывает один клиент; главное отличие там fork где-то в первом. Если реализованный вами протокол совершенно сложный, управление конечным автоматом для нескольких клиентов одновременно становится довольно сложным, тогда как потоки позволяют вам просто script общаться с одним клиентом. Код легче получить, и его легче понять и поддерживать.

  • обратные вызовы в одном потоке ОС - это совместная многозадачность, в отличие от упреждающей многозадачности, которая является тем, что вы получаете с потоками. Основным недостатком совместной многозадачности является то, что программист несет ответственность за то, чтобы не было голода. Он теряет модульность: совершает ошибку в одном месте, и это может испортить всю систему. Это действительно то, о чем вы не хотите беспокоиться, а превенция - простое решение. Более того, связь между обратными вызовами невозможна (это будет тупик).

  • concurrency не является трудным в Haskell, потому что большинство кода является чистым и поэтому поточно-безопасным по конструкции. Есть простые примитивы общения. Гораздо труднее стрелять в ногу с помощью concurrency в Haskell, чем на языке с неограниченными побочными эффектами.

Ответ 2

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

Да, на самом деле события и потоки объединены в Haskell.

  • Вы можете программировать в явных потоках (например, миллионы потоков на одном ноутбуке).
  • Или; вы можете запрограммировать стиль async-событий, основанный на масштабируемом уведомлении о событиях.

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

например. для

Параллельные коллекции на 32 ядрах

alt text

В Haskell у вас есть как события, так и потоки, а также все события под капотом.

Прочитайте документ, описывающий реализацию.

Ответ 3

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

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

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

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

У вас все еще может быть состояние гонки в node.js, но это сложнее.

Каждый запрос есть в нем собственный поток. Когда вы пишете код, который должен взаимодействовать с другими потоками, очень просто сделать его потокобезопасным благодаря примитивам haskell concurrency.

Хороший и простой UNIX-API. Бонус: отличная поддержка HTTP. Также доступен DNS.

Взгляните на хакеры и убедитесь сами.

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

У вас нет таких проблем, ghc будет распространять вашу работу среди реальных потоков ОС.

Одинаковый язык для клиентской и серверной сторон. (Я не вижу слишком большого значения в этом, однако JQuery и node.js используют модель программирования событий, но все остальное очень различно. Я просто не вижу, как код обмена между серверной и клиент- сторона может быть полезна на практике.)

Хаскелл не может победить здесь... верно? Подумайте еще раз, http://www.haskell.org/haskellwiki/Haskell_in_web_browser.

Все это упаковано в один продукт.

Загрузите ghc, запустите cabal. Там пакет для каждой потребности.

Ответ 4

Я лично вижу Node.js и программирование с обратными вызовами как излишне низкоуровневое и немного неестественное. Почему программа с обратными вызовами, когда хорошая среда выполнения, такая как найденная в GHC, может обрабатывать обратные вызовы для вас и делать это довольно эффективно?

В то же время время выполнения GHC значительно улучшилось: теперь он имеет новый "новый менеджер IO", называемый MIO, где "M" означает multicore Я верю. Он основывается на создании существующего менеджера IO, и его основной задачей является преодоление причины ухудшения производительности 4+ ядер. Показатели производительности, представленные в этой статье, впечатляют. Смотрите сами:

С Mio реалистичные HTTP-серверы в масштабе Haskell до 20 ядер процессора достигают максимальной производительности до 6,5x по сравнению с теми же серверами, что и предыдущие версии GHC. Также улучшена латентность серверов Haskell: [...] при умеренной нагрузке уменьшает ожидаемое время отклика на 5.7x по сравнению с предыдущими версиями GHC

и

Мы также показываем, что с Mio McNettle (контроллер SDN, написанный в Haskell) может эффективно масштабировать до 40+ ядер, достигать более 20 миллионов новых запросов в секунду на одной машине и, следовательно, стать самым быстрым из всех существующих контроллеров SDN.

Mio превратилась в выпуск GHC 7.8.1. Я лично вижу это как важный шаг вперед в исполнении Haskell. Было бы очень интересно сравнить производительность существующих веб-приложений, собранную предыдущей версией GHC и 7.8.1.

Ответ 5

Вопрос довольно нелепо, потому что 1) Хаскелл уже решил эту проблему гораздо лучше и 2) примерно так же, как это сделал Эрланг. Вот сравнительный тест против node: http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks

Дайте Haskell 4 ядра, и он может делать 100k (простых) запросов в секунду в одном приложении. Node не может делать столько же и не может масштабировать одно приложение по всем ядрам. И вам не нужно ничего делать, чтобы воспользоваться этим, потому что время выполнения Haskell не блокируется. Единственным другим (относительно общим) языком, который имеет неблокирующий IO, встроенный во время выполнения, является Erlang.

Ответ 6

События IMHO хороши, но программирование с помощью обратных вызовов не является.

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

Можно сказать, что проблемы похожи на программирование GUI, где модель событий работает нормально, но графические интерфейсы не имеют навигации и не имеют кнопки возврата. Это умножает возможные переходы состояний в веб-приложениях. Результатом попытки решить эту проблему являются тяжелые каркасы со сложными конфигурациями с множеством распространенных магических идентификаторов, не подвергая сомнению корень проблемы: модель обратного вызова и присущее ей отсутствие совместного использования областей видимости и отсутствие последовательности, поэтому последовательность должна быть построено путем связывания идентификаторов.

Существуют основанные на последовательностях фреймворки, такие как ocsigen (ocaml) seaside (smalltalk) WASH (прекращено, Haskell) и mflow (Haskell), которые решают проблему управления государством, сохраняя навигацию и REST-полноту. в этих рамках программист может выразить навигацию как императивную последовательность, где программа отправляет страницы и ждет ответов в одном потоке, переменные находятся в области действия, а кнопка "Назад" работает автоматически. Это по своей сути создает более короткий, более безопасный, более читаемый код, где навигация ясно видна программисту. (справедливое предупреждение: я разработчик mflow)