Comments 155
Мы пришли к Erlang + Elixir (в тех местах где у вас python, а у нас ruby; ruby пока ещё есть местами). По поводу библиотек — проблема преувеличена, почти везде проблема найти хорошую: Python+Twisted или Ruby + EM или Scala + Akka и вы внезапно не можете нормально пользовать большинство библиотек, потому, что их авторы не знали, что иногда надо асинхронно.
В разрезе эпрланга и акторной модели как не вспомнить Celluloid
ЕМНИП он не работал и не работает. Чисто на поиграть.
Заявление ни о чем.
У нас несколько сервисов написаны с использованием Celluloid.
Sidekiq v3.x использовал Celluloid.
У нас несколько сервисов написаны с использованием Celluloid.
Sidekiq v3.x использовал Celluloid.
Мне казалось там по треду на актора, может путаю с другой библиотекой или уже лучше стало. Во-вторых, даже если там всё хорошо уже — какую долю руби-экосистемы можно реально использовать совместно с ним?
Уточнение: мы используем только Jruby.
Вот, господа минусующие, вы бы хоть поправили меня. Я вполне готов принять тот факт, что в celluloid всё хорошо, а у меня старая или просто неверная информация.
Использовал и отказался. Да, он дает абстаркцию, за которую надо платить производительностью.
Спасибо за статью. Недавно еще обнаружил такую штуку — по сути реализация эрланга на джаве: http://www.paralleluniverse.co/quasar/ прям с собственным планировщиком, процессами, бехейвиорами и тд и тп.
Опыт Akka показывает что JVM плохо подходит для акторной модели. В Quasar как-то смогли обойти все ее ограничения?
"Какие ваши доказательства?"
Не наезда ради для. Правда интересно.
Мне из минусов JVM кроме общей кучи (и как следствие stop-the-world) ничего в голову, просто, не приходит.
Не наезда ради для. Правда интересно.
Мне из минусов JVM кроме общей кучи (и как следствие stop-the-world) ничего в голову, просто, не приходит.
Почти ничего из библиотек не в курсе того, что их пытаются вот так вот пользовать => непредсказуемое поведение в продакшене.
И какая из существующих VM успешно справилась с этим?
Речь, я полагаю, о блокирующих вызовах, укладывающих шедулер?
Речь, я полагаю, о блокирующих вызовах, укладывающих шедулер?
Тут либо то что вы озвучили, либо квазаропроблемы (назовём это так, хотя такие же проблемы у em-synchrony).
В первом случае у BEAM (Erlang) всё очень хорошо пока вы не зовёте С, при этом в FFI есть довольно много возможностей дружить с VM. В Haskell всё тоже отлично в пределах языка с его спарками. В Go можно смело блокироваться на IO, но вот на вычислениях не стоит. Больше — не в курсе.
Квазаро-проблемы это ситуация, когда в виртуальную машину где вообще-говоря не стоит блокировать притаскивают каким-то способом а-ля-эрланг вытесняющую многозадачность, но для поддержки этого типично оно переписывает байткод или делает какой-нибудь monkey-patching (в случае em-synchrony) и в результате у нас сторонняя библиотека оказывается не совсем тем, что написал и протестировал её автор.
В первом случае у BEAM (Erlang) всё очень хорошо пока вы не зовёте С, при этом в FFI есть довольно много возможностей дружить с VM. В Haskell всё тоже отлично в пределах языка с его спарками. В Go можно смело блокироваться на IO, но вот на вычислениях не стоит. Больше — не в курсе.
Квазаро-проблемы это ситуация, когда в виртуальную машину где вообще-говоря не стоит блокировать притаскивают каким-то способом а-ля-эрланг вытесняющую многозадачность, но для поддержки этого типично оно переписывает байткод или делает какой-нибудь monkey-patching (в случае em-synchrony) и в результате у нас сторонняя библиотека оказывается не совсем тем, что написал и протестировал её автор.
>> Go можно смело блокироваться на IO
На сетевое IO. Файловое, консольное, subprocess — блокируют тред планировщика.
На сетевое IO. Файловое, консольное, subprocess — блокируют тред планировщика.
Нда, всё печальнее, чем я думал :( Как гоферы живут тогда если файлы и подпроцессы нельзя трогать без блокировки?
Ну, в случае чего, рантайм создаст новый тред.
Живут они с надеждой на лучшее, наверное.
В принципе, можно вынести такие операции в отдельный ограниченный пул горутин, в этом случае, когда все станет плохо, система в целом может и не развалиться.
Живут они с надеждой на лучшее, наверное.
В принципе, можно вынести такие операции в отдельный ограниченный пул горутин, в этом случае, когда все станет плохо, система в целом может и не развалиться.
Дорогие нити. В виртуальной машине Erlang поддерживается пул системных нитей, которые выполняют его процессы, при этом стандартнаяя библиотека позволяет блокировать процесс, переиспользую нить. В JVM в акторах выполнять блокирующие операции не рекомендуется, так как они блокируют и нить из пула. Это очень мешает программированию. Как это решается в Quasar я при беглом взгяде не понял.
В Erlang очереди сообщений интегрированы с планировщиком. Процессы, которые вызывают риск переполнения чьего-нибудь mailbox, выполняются медленнее, позволяя его разгрести. В JVM эти понятия реализуются сильно на разных уровнях и реализовать такое поведение будет довольно сложно.
В Erlang очереди сообщений интегрированы с планировщиком. Процессы, которые вызывают риск переполнения чьего-нибудь mailbox, выполняются медленнее, позволяя его разгрести. В JVM эти понятия реализуются сильно на разных уровнях и реализовать такое поведение будет довольно сложно.
В JVM в акторах выполнять блокирующие операции не рекомендуется, так как они блокируют и нить из пула.Не так. Рекомендуется для акторов с блокирующими операциями выделять отдельный пул. Делается это через конфиг акки.
Дорогие нити. В виртуальной машине Erlang поддерживается пул системных нитей, которые выполняют его процессы, при этом стандартнаяя библиотека позволяет блокировать процесс, переиспользую нить. В JVM в акторах выполнять блокирующие операции не рекомендуется, так как они блокируют и нить из пула. Это очень мешает программированию. Как это решается в Quasar я при беглом взгяде не понял.
В Akka акторы — это просто объекты со сравнимым с Эрланговым оверхедом (около 300 байт).
Шедулер ActorSystem'а Akka'и — это просто "реактор", который занимается разрешением фьючеров в готовые значения.
Немногим отличается от beam, который периодически дает процессорное время эрло-процессам. А процессы совершают редукции, пока не получат готовые значения.
Да, Akka'у можно повесить вызвав, что-нибудь блокирующее из сторонней библиотеки. Но и beam тоже не оценит, вызов долгоиграющего NIF'а.
И в том, и в другом случае, обязательно надо знать, что за функции вызываешь. Казалось бы, очевидно...
Процессы, которые вызывают риск переполнения чьего-нибудь mailbox, выполняются медленнее, позволяя его разгрести.
Ahem. Насколько мне известно, erlang:send/2 может заблокировать исключительно по причине большого размера сообщения или из-за того, что слать надо на другую ноду (отсюда и появился erlang:send_nosuspend/2).
Проблемы консумера, неуспевающего прожёвывать свою очередь, положено решать отказывая в обслуживании (см. https://github.com/ferd/pobox).
Мне кажется не стоит смешивать тёплое с мягким: в Akka любая библиотека, не умеющая в футуры (или хотя бы коллбэки) делает плохо. В Erlang/Elixir/Haskell поставить колом VM библиотекой только на этом языке (без вызовов в C) существенно тяжелее. Но есть общие для языков проблемы вроде "нужна библиотека которая не делает X, потому, что так нельзя под нагрузкой" (где X может быть специфично для языка или vm), которые внезапно выравнивают число юзабельных библиотек.
Процессы, которые вызывают риск переполнения чьего-нибудь mailbox, выполняются медленнее, позволяя его разгрести.
Если вы про sender punish, который вроде (к моему ужасу :( ) умолчально включен, то он не очень работает. В противном случае, при избыточном логгировании, система прекращала бы работать до того, как сожрет всю память очередью gen_event'а логгера.
Похоже она всё же есть
https://github.com/erlang/otp/blob/maint/erts/emulator/beam/bif.c#L2105
Если покопаться, то видно, что у процесса списывается редукций
https://github.com/erlang/otp/blob/maint/erts/emulator/beam/bif.c#L2105
Если покопаться, то видно, что у процесса списывается редукций
4 * количество сообщений в мейлбоксе получателя
.Обидно, наказывают, того, кто уже капнул сообщением. Тем самым предоставляя преимущество тем, кто только собирается усугубить положение процесса с переполненным мейлбоксом. :D
UFO just landed and posted this here
капля дегтя: этими нитками для асинхронной работы в эрланге нельзя управлять. Их количество нельзя менять в рантайме и из эрланга нельзя указать на каком пуле ниток запускать этот драйвер.
Можно, наверное, запускать с запасом, а в рантайме менять
Так там всего один пул. Точнее, пул планировщиков и пул IO и dirty schedulers, но драйверы (если ниче не путаю) всегда на пуле планировщиков исполняются (явно скидывая IO в пул IO). Или что имеется в виду?
erlang:system_flag(schedulers_online, N)
.нельзя указать на каком пуле ниток запускать этот драйвер
Так там всего один пул. Точнее, пул планировщиков и пул IO и dirty schedulers, но драйверы (если ниче не путаю) всегда на пуле планировщиков исполняются (явно скидывая IO в пул IO). Или что имеется в виду?
В этом есть и важные плюсы — в большентсве случаев упрощает разработку и снижает порог вхождения.
общая куча — это не только stop the world, но и нереальная сложность в том, что бы устранить все утечки памяти.
Я же говорю, там свои треды, свой планировщик, свои мейлбоксы опять же. Точно так же как на evm, создатели руководствовались своим опытом использования эрланга.
А можно пару слов про то, как там решается вопрос с переиспользованием потоков? По идее тут без кодогенерации не обойтись.
У них в статейке основной это написано (мне лень переводить)):
Of the three pieces, coroutines are the most challenging to implement on the JVM, as they require bytecode instrumentation. Essentially, every possibly-pausing method (the Quasar/Pulsar nomenclature is “suspendable”) must be inspected to find all invocations of other suspendable methods. Before the call to a suspendable method, code must be injected to push the caller’s local variables onto a stack object. Also, code must be injected to the beginning of every suspendable method, that upon resuming would jump to the instruction following the pause-point. This has to be done to all suspendable methods on the (OS thread) stack.
Можно сказать, эта статья — перевод двух моих rant'ов :)
medium.com/@dmitriid/erlang-is-dead-long-live-e-885ccbcbc01f
medium.com/@dmitriid/designing-for-anything-with-erlang-cfadb6833bc0
medium.com/@dmitriid/erlang-is-dead-long-live-e-885ccbcbc01f
medium.com/@dmitriid/designing-for-anything-with-erlang-cfadb6833bc0
Синтаксис Erlang основан на его предке — языке Prolog. Когда-то этот язык было модно учить — относительно простой и выгладещий перспективно. Но развитие ИИ пошло в другую сторону, и современной молодежи такой синтаксис становится непонятным.
ФП как раз наиболее полезно для новичков. Оно сильно мешает писать плохой код.
ФП как раз наиболее полезно для новичков. Оно сильно мешает писать плохой код.
Та или иная парадигма сама по себе не защищает от плохого кода. И тут дело не в парадигме, а в том, что это редко используемая технология. Значит, ей интересуются любопытные разработчики, а нелюбопытные игнорируют.
Вообще любопытство разработчика хорошо коррелирует с его способностью писать хороший код :)
Вообще любопытство разработчика хорошо коррелирует с его способностью писать хороший код :)
На самом деле писать плохой код на эрланге проще простого, если нету понимания как работает этот язык. Никогда не забуду функцию проверяющую сложность пароля и состоящую из 15(!) вложенных операторов case of. То есть человек просто взял и написал код так как если бы он писал его на с. Переписанный код с применением pattern-matching занял в 4 раза меньше места.
Не мешает. Просто вокруг меньше людей которые понимают, что код плохой.
А я уверен, что у Erlang прекрасный синтаксис, который идеально укладывается в (мое) видение языка. Я воспринимаю отдельную функцию как систему фильтров, через которые текут входные данные, и тут синтаксис Erlang идеален.
И насчет веба я не совсем согласен. Есть же Chicago Boss. Он менее изящный, чем RoR или Phoenix, но он работает.
И насчет веба я не совсем согласен. Есть же Chicago Boss. Он менее изящный, чем RoR или Phoenix, но он работает.
Это в значительной мере дело вкуса. Но кое-где есть объективные проблемы. Например, некоторым новичкам требуются значительные усилия, чтобы разобраться, где ставить точку, где точку с запятой, а где просто запятую. Достаточно понаблюдать немного за тем, как пишут код новички, чтобы понять, что проблема есть)
Увы, мы не знаем никого, кто использует Chicago Boss. В этом отношении даже Elixir/Phoenix лучше. Ибо есть разработчики = есть у кого попросить о помощи в случае проблем.
Увы, мы не знаем никого, кто использует Chicago Boss. В этом отношении даже Elixir/Phoenix лучше. Ибо есть разработчики = есть у кого попросить о помощи в случае проблем.
мы использовали, поиграли и отложили.
Эрланг своей иммутабельностью делает кошмарным использование ORM в стиле рельс: никакого кеширования, мемоизации и прочего
Эрланг своей иммутабельностью делает кошмарным использование ORM в стиле рельс: никакого кеширования, мемоизации и прочего
Речь про Ecto или про boss_db? Как давно это было?
boss_db, года 3 назад.
С эликсиром мы так и не разобрались, если честно.
С эликсиром мы так и не разобрались, если честно.
У меня очень позитивные впечатления от Ecto, мы вроде бы уже общались на эту тему в рассылке. Оно впрочем не пытается быть rails-like. Мемоизации нет, кэширование есть, N+1 решается до того как запрос вообще окажется сериализован в SQL.
Я думаю, речь про BossDB. Как использовать Ecto из pure-erlang-проекта так, чтобы это не было болью, пока не очень ясно.
upd: давно не обновлял страницу
upd: давно не обновлял страницу
Не уверен, что это хорошая идея вообще. Я бы делал DAO-слой на Elixir, и уже с ним общался бы из Erlang.
Что-то такое я и подразумевал. Но даже это уже сделать без замены сборщика на mix, что уже малоприятно.
звучит как-то малоперспективно. Прописывать все функции бизнес-логики =(
Я сделал ecto_mnesia нативный враппер, сейчас он зарефакторен под лейблом Nebo15:
https://github.com/Nebo15/ecto_mnesia
Попробуйте его
https://github.com/Nebo15/ecto_mnesia
Попробуйте его
Недавно еще lfe(https://github.com/rvirding/lfe) зарелизился. для любителей)
Хотел бы поблагодарить автора за отличный курс на хекслете. Спасибо.
По-моему, Elixir как раз устраняет большую часть перечисленных вами минусов.
Я тоже в прошлом году проводил сравнение Go и Elixir для узких мест. В итоге победил Elixir.
Наиболее удивительным для меня фактом было то, что экосистема Elixir оказалась более зрелой, чем у Go. Несмотря на то, что Go на несколько лет старше, в его экосистеме до сих пор преобладает хаос и анархия. И при выборе библиотек остаётся только удивляться насколько распространен среди гоферов NIH-синдром.
Я тоже в прошлом году проводил сравнение Go и Elixir для узких мест. В итоге победил Elixir.
Наиболее удивительным для меня фактом было то, что экосистема Elixir оказалась более зрелой, чем у Go. Несмотря на то, что Go на несколько лет старше, в его экосистеме до сих пор преобладает хаос и анархия. И при выборе библиотек остаётся только удивляться насколько распространен среди гоферов NIH-синдром.
В теории да, поэтому мы его и пробуем. А как оно получится на практике — увидим)
Несмотря на то, что Go на несколько лет старше, в его экосистеме до сих пор преобладает хаос и анархия
так пользуйтесь стандартной либой. зачем тащить всякое стороннее говно в проект когда почти все есть в стандартной библиотеке
так пользуйтесь стандартной либой. зачем тащить всякое стороннее говно в проект когда почти все есть в стандартной библиотеке
Несколько раз пытался разобраться в Erlang/OTP и кроме недостатка литературы, о котором сказано в статье, натыкался на то, что я совсем не понимаю, как работать с состояниями и вводом-выводом (допускаю, что я просто глуп).
По какой-то причине большинство статей о функциональных языках описывают разнообразные простые понятия: чистые функции, рекурсия, частичное применение, каррирование и так далее. В лучшем случае, про Erlang напишут как использовать gen_server. Все это любопытно, но не является чем-то действительно необычным или сложным для человека, который писал на современных языках.
А вот как правильно хранить состояние, когда оно реально необходимо? Знаю есть несколько способов, но какой лучше и в каких условиях? Может лучше вообще всегда отдавать состояние на сторону (в Redis, например)? Или как платформа переваривает обращение к «грязным» функциям из модуля file? Это же невозможно (точнее не гарантирован корректный результат) в чистом функциональном языке, значит есть какой-то обходной путь? Я нашел всего несколько статей на эту тему, они были полезны, но я по-прежнему не могу сказать, что эта тема стала мне понятна.
По какой-то причине большинство статей о функциональных языках описывают разнообразные простые понятия: чистые функции, рекурсия, частичное применение, каррирование и так далее. В лучшем случае, про Erlang напишут как использовать gen_server. Все это любопытно, но не является чем-то действительно необычным или сложным для человека, который писал на современных языках.
А вот как правильно хранить состояние, когда оно реально необходимо? Знаю есть несколько способов, но какой лучше и в каких условиях? Может лучше вообще всегда отдавать состояние на сторону (в Redis, например)? Или как платформа переваривает обращение к «грязным» функциям из модуля file? Это же невозможно (точнее не гарантирован корректный результат) в чистом функциональном языке, значит есть какой-то обходной путь? Я нашел всего несколько статей на эту тему, они были полезны, но я по-прежнему не могу сказать, что эта тема стала мне понятна.
Вопрос больше касается чистых функциональных языков, например Haskell. А про Haskell рассказать кратко я не могу)
Что касается Erlang, то в нем можно (и нужно) делать грязные функции, и с вводом-выводом никаких сложностей нет. Для хранения состояния — gen_server. Ну а в целом применение Erlang на практике хорошо изложено в книге Фреда Хеберта Learn you some Erlang. Ну и в моем учебном курсе тоже :)
Что касается Erlang, то в нем можно (и нужно) делать грязные функции, и с вводом-выводом никаких сложностей нет. Для хранения состояния — gen_server. Ну а в целом применение Erlang на практике хорошо изложено в книге Фреда Хеберта Learn you some Erlang. Ну и в моем учебном курсе тоже :)
За ссылки почитаю, спасибо.
В смысле возврат функции с новым состоянием? Что-то типа:
Это относительно понятный код. Хотя весьма любопытно что там под капотом. Я так понимаю, что на уровне машинных кодов мы здесь просто обновляем значения в стеке.
Для хранения состояния — gen_server.
В смысле возврат функции с новым состоянием? Что-то типа:
server(State)
receive
{async, Message} ->
NewState = do_something(State,Message),
server(NewState);
end.
Это относительно понятный код. Хотя весьма любопытно что там под капотом. Я так понимаю, что на уровне машинных кодов мы здесь просто обновляем значения в стеке.
Новосконструированные значения занимают новое положение на куче. Куча у каждого процесса своя.
Периодически (при достижении fullsweep или при уходе в hibernate) срабатывает GC и проходится по всей куче, удаляя ненужные значения и уплотняя старые.
Факт того, что все структуры данных в Эрланге персистентные (иммутабельные, функциональные) позволяет заявлять, что ссылки в куче "направлены в одну сторону": благодаря этому можно чистить кучу в один проход.
Таким образом, в Эрланге есть stop-the-world, просто он у каждого процесса свой, и длится недолго :)
Периодически (при достижении fullsweep или при уходе в hibernate) срабатывает GC и проходится по всей куче, удаляя ненужные значения и уплотняя старые.
Факт того, что все структуры данных в Эрланге персистентные (иммутабельные, функциональные) позволяет заявлять, что ссылки в куче "направлены в одну сторону": благодаря этому можно чистить кучу в один проход.
Таким образом, в Эрланге есть stop-the-world, просто он у каждого процесса свой, и длится недолго :)
Нет, не совсем так. Это достаточно долгая история, в двух словах не объяснишь.
Посмотрите здесь https://ru.hexlet.io/courses/erlang_101/lessons/practical_erlang_gen_server/theory_unit
Посмотрите здесь https://ru.hexlet.io/courses/erlang_101/lessons/practical_erlang_gen_server/theory_unit
Может лучше вообще всегда отдавать состояние на сторону (в Redis, например)?
Если действительно нужно хранить стейт (я убежден, что во многих случаях без него можно обойтись, это больше психологическая проблема), то всегда доступен встроенный ETS.
Отнюдь, stateful app + sticky sessions = приложение которому не надо ходить в базу на каждый чих. Очень полезно например в играх.
ets не всегда нужен, иногда достаточно отдельного процесса с кэшем, который логически располагается между, условно, БД и процессом-обработчиком запроса.
В приведённом примере он нужен как минимум чтобы найти процесс, отвечающий за стейт пользователя.
Ну, этот ets спрятан в процессе-регистраторе, и его может и не быть. Может, в нем для простоты map хранится.
А без процесса-регистратора все равно не выйдет, потому что без него получается классический race condition «регистрация после старта».
Ладно, может и выйдет, но я не могу так навскидку представить, как это реализовать.
А без процесса-регистратора все равно не выйдет, потому что без него получается классический race condition «регистрация после старта».
Ладно, может и выйдет, но я не могу так навскидку представить, как это реализовать.
Не очень понял про рейс "регистрация после старта".
Как бы то ни было, без спец-процесса не выйдет — нужно де-регистривоать по 'DOWN', и ETS в любом случае завернут будет. Мой поинт однако в том, что ETS это инструмент, который активно пользуется и которым не стоит пренебрегать.
Как бы то ни было, без спец-процесса не выйдет — нужно де-регистривоать по 'DOWN', и ETS в любом случае завернут будет. Мой поинт однако в том, что ETS это инструмент, который активно пользуется и которым не стоит пренебрегать.
Конечно, я не агитирую против использования ETS, я просто предостерегаю от необдуманого использования.
Вкратце, про рейс — если старт регистрируемого процесса происходит не в процессе-регистраторе, мы можем попасть в ситуацию, когда мы стартовали два инстанса регистрируемого процесса, один успешно регистрируется, попытка регистрации второго приводит к ошибке already_registered. Решается, насколько мне известно, только синхронным запуском процессов через регистратор, причем, я не уверен, является ли gproc:reg_or_locate/3 правильной реализацией.
Вкратце, про рейс — если старт регистрируемого процесса происходит не в процессе-регистраторе, мы можем попасть в ситуацию, когда мы стартовали два инстанса регистрируемого процесса, один успешно регистрируется, попытка регистрации второго приводит к ошибке already_registered. Решается, насколько мне известно, только синхронным запуском процессов через регистратор, причем, я не уверен, является ли gproc:reg_or_locate/3 правильной реализацией.
Я бы не сказал, что это прям таки рейс —
already_registered
ничто не мешает обработать и отвалиться, под simple_one_for_one
с temporary
детьми это вполне нормально работать будет.Ну, технически это все-таки рейс.
Конечно, тут все сильно зависит от того, что мы пытались стартовать, зачем, как это обработается клиентом, если он есть, etc.
Конечно, тут все сильно зависит от того, что мы пытались стартовать, зачем, как это обработается клиентом, если он есть, etc.
A race condition or race hazard is the behavior of an electronic, software or other system where the output is dependent on the sequence or timing of other uncontrollable events.en.wikipedia.org/wiki/Race_condition
Тут результат не будет зависеть от порядка — останется ровно один живой процесс, ответственный за пользователя; на него будет резолвиться имя.
Если вызывавшая сторона делала что-то вроде `where` то он, при корректной реализации, дождется победителя и вернет его или отвалится по таймауту.
По моему опыту, вызывающая сторона чаще всего делает не where, а find_or_start, в котором и прячется внезапный рейс. А так как вызвающая сторона — процесс, с которым общается клиент, это чревато получением клиентом ошибки.
Это примерно такая же частая ошибка новичков, как упомянутый в статье дедлок gen_server:call.
Это примерно такая же частая ошибка новичков, как упомянутый в статье дедлок gen_server:call.
вот мы себе специально для этого сделали в gen_tracker механизм вменяемого неблокирующего, но атомарного старта
не читайте про эрланг как про функциональный язык.
Эрланг — это язык + платформа для написания сетевых сервисов. Забудьте про каррирование, речь идет о том, как сделать код, который можно будет обслуживать в продакшне
Эрланг — это язык + платформа для написания сетевых сервисов. Забудьте про каррирование, речь идет о том, как сделать код, который можно будет обслуживать в продакшне
Довольно интересный обзор языка. Может стоило немножко поделиться опытом, например, как именно решаются проблеммы со строками, драйвером MySQL и как обнаружить переполнение mailbox? Как любитель Erlang, с удовольствием прочитал бы!
Смущает один момент: проблемма именования переменных «Var1, Var2, Var3» как-то смахивает на проблемму разработчика, а не языка. Или я не понял контекста?
Смущает один момент: проблемма именования переменных «Var1, Var2, Var3» как-то смахивает на проблемму разработчика, а не языка. Или я не понял контекста?
А Вы рассматривали как альтернативу Erlang — Haskell. Насколько известно, у него есть достаточно удачные проекты для web, тот же WARP, yesod.
С Haskell многие из нас знакомы, но как язык для разработки веб-сервисов мы его не рассматриваем. Основная причина — нет накопленного индустрией опыта разработки и поддержки крупных веб-проектов. Ну например, в 19:05 внезапно на 200% выросло время ответа сервиса на http-запросы клиентов. Что делать, как с этим разбираться? С Erlang и Python мы знаем что делать, а с Haskell нет.
Erlang обладает ужасным синтаксисом, который заставляет страдать
Интересное мнение. У меня получилось наоборот. Есть tsung — система нагрузочного тестирования, написанная на эрланге. Несколько лет назад писал плагин для него(он поддерживает основные сетевые протоколы, но у нас был свой собственный, бинарный). Основы языка действительно изучаются довольно быстро, он ну очень простой, проще разве что только луа, синтаксис очень понравился, но это конечно вкусовщина.
строками пользоваться не нужно, а использовать только binary
поддерживаю, благодаря паттерн матчингу разбирать бинарные данные одно удовольствие и выглядит все это очень декларативно. Кстати, почему не упомянули об этом в статье, ведь это одно из основных достоинств языка
Интересное мнение. У меня получилось наоборот. Есть tsung — система нагрузочного тестирования, написанная на эрланге. Несколько лет назад писал плагин для него(он поддерживает основные сетевые протоколы, но у нас был свой собственный, бинарный). Основы языка действительно изучаются довольно быстро, он ну очень простой, проще разве что только луа, синтаксис очень понравился, но это конечно вкусовщина.
строками пользоваться не нужно, а использовать только binary
поддерживаю, благодаря паттерн матчингу разбирать бинарные данные одно удовольствие и выглядит все это очень декларативно. Кстати, почему не упомянули об этом в статье, ведь это одно из основных достоинств языка
Если позволите, хотелось бы оставить пару ссылок на статьи со своими впечатлениями — раз и два. В дополнение хотелось бы сказать следующее.
В Erlang меня очень беспокоила скорость выполнения кода. Рабочая версия, что был выбран неподходящий под задачу язык, нужно было реально много считать, а Erlang тут не блещет. Также мне лично очень не хватало статической типизации в языке. Dialyzer — не то, слишком медленный, слишком прожорливый, находит далеко не все, половина разработчиков на него забивают. Ну и библиотеки, конечно же.
После Erlang писал на Scala+Akka (тут про впечатления). Хочу сказать, что боли заметно меньше, так как все названные проблему реально решены. Ну и как бонус область применения заметно шире, в частности коллеги вполне успешно разрабатывали на Scala под Android. Если найти сеньера, который будет бить по рукам за Scalaz, Akka Cluster и Shapeless, все будет хорошо. Больше всего неудобств доставляла необходимость изображать легковесные процессы вручную на футурах. Это не сложно, но по неопотности можно собрать кучу гонок и других косяков.
В настоящее время думается что оптимальный вариант для прикладного программирования — это все-таки Go. В нем решены все озвученные выше проблемы, плюс область применения еще шире, плюс для программирования на Go не требуется тяжелой IDE, можно обойтись простым Sublime Text. И на выходе не получаются jar-ники по 100-200 Мб размером.
В Erlang меня очень беспокоила скорость выполнения кода. Рабочая версия, что был выбран неподходящий под задачу язык, нужно было реально много считать, а Erlang тут не блещет. Также мне лично очень не хватало статической типизации в языке. Dialyzer — не то, слишком медленный, слишком прожорливый, находит далеко не все, половина разработчиков на него забивают. Ну и библиотеки, конечно же.
После Erlang писал на Scala+Akka (тут про впечатления). Хочу сказать, что боли заметно меньше, так как все названные проблему реально решены. Ну и как бонус область применения заметно шире, в частности коллеги вполне успешно разрабатывали на Scala под Android. Если найти сеньера, который будет бить по рукам за Scalaz, Akka Cluster и Shapeless, все будет хорошо. Больше всего неудобств доставляла необходимость изображать легковесные процессы вручную на футурах. Это не сложно, но по неопотности можно собрать кучу гонок и других косяков.
В настоящее время думается что оптимальный вариант для прикладного программирования — это все-таки Go. В нем решены все озвученные выше проблемы, плюс область применения еще шире, плюс для программирования на Go не требуется тяжелой IDE, можно обойтись простым Sublime Text. И на выходе не получаются jar-ники по 100-200 Мб размером.
Не нужно внешнее in-memory хранилище (Radis, memchached), можно держать кэш прямо в оперативной памяти сервиса.
Можете подробнее обьяснить на счет этого?
В стандартной библиотеке Erlang есть решения, позволяющие обойтись без внешних программ для хранения кеша: http://erlang.org/doc/efficiency_guide/tablesDatabases.html
На Хабре тоже этой темы касались: https://habrahabr.ru/post/245135/
На Хабре тоже этой темы касались: https://habrahabr.ru/post/245135/
я думаю речь идет о http://erlang.org/doc/man/ets.html
Возьмем для простоты обработку HTTP-запросов с пользовательскими сессиями.
Наиболее распространенная на сегодняшний день модель — у нас есть N воркеров в виде независимых процессов, по ним round robin распределяются запросы пользователей. Все вроде бы работает, но для хранения сессии между запросами нам нужно либо прикреплять пользователей к воркерам, что не очень удобно, либо иметь некое внешнее хранилище для всех сессий — собственно, redis или memcached.
В erlang подход несколько другой — мы запускаем один процесс ОС, в рамках которого на N ОС-тредах выполняется куча легковесных процессов(акторов), которые и выполняют пользовательские запросы. Причем, на каждый запрос создается новый актор, который умирает после ответа. Акторы дешевые, мы можем себе позволить такую модель выполнения.
При этом сессии мы храним
— либо в одном отдельном акторе — плохо, потому что, ботлнек.
— либо в отдельном акторе на каждую сессию, время жизни которого слабо связано с актором-исполнителем запроса. Акторы-сессии идентифицируются ключем сессии. Это метод хранения не-shared данных.
— либо, advanced level, в ets — in-memory-таблице, позволяющей доступ из нескольких процессов. Это для shared данных, вроде кэшей. В случае возникновения data race добавить дополнительные акторы, разруливающие запросы на запись.
Любой из перечисленных способов быстрее хождения за данными в другой ОС процесс.
Если не вдаваться в подробности — все.
Наиболее распространенная на сегодняшний день модель — у нас есть N воркеров в виде независимых процессов, по ним round robin распределяются запросы пользователей. Все вроде бы работает, но для хранения сессии между запросами нам нужно либо прикреплять пользователей к воркерам, что не очень удобно, либо иметь некое внешнее хранилище для всех сессий — собственно, redis или memcached.
В erlang подход несколько другой — мы запускаем один процесс ОС, в рамках которого на N ОС-тредах выполняется куча легковесных процессов(акторов), которые и выполняют пользовательские запросы. Причем, на каждый запрос создается новый актор, который умирает после ответа. Акторы дешевые, мы можем себе позволить такую модель выполнения.
При этом сессии мы храним
— либо в одном отдельном акторе — плохо, потому что, ботлнек.
— либо в отдельном акторе на каждую сессию, время жизни которого слабо связано с актором-исполнителем запроса. Акторы-сессии идентифицируются ключем сессии. Это метод хранения не-shared данных.
— либо, advanced level, в ets — in-memory-таблице, позволяющей доступ из нескольких процессов. Это для shared данных, вроде кэшей. В случае возникновения data race добавить дополнительные акторы, разруливающие запросы на запись.
Любой из перечисленных способов быстрее хождения за данными в другой ОС процесс.
Если не вдаваться в подробности — все.
вроде же можно распределять программу на несколько серверов, т.е. map такой распрёделённый получится
в этом случае это как по скорости работает, не тестировали?
в этом случае это как по скорости работает, не тестировали?
Map-reduce это довольно частный случай. Можно разные стадии обработки держать на разных машинах, можно пабсаб, можно писать поверх riak_core, можно использовать подход актор-на-пользователя с регистрацией в etcd (или чём угодно таком). Много как можно одно приложение намазать на кластер и не только в Erlang.
> можно распределять программу на несколько серверов
Можно, но это уже не новичковый уровень. Я, честно говоря, никогда не испытывал нужды в Erlang distribution, поэтому знаю о нем очень мало, штука довольно неоднозначная. Скажем, WhatsApp используют его, но они и умеют его правильно готовить.
Можно, но это уже не новичковый уровень. Я, честно говоря, никогда не испытывал нужды в Erlang distribution, поэтому знаю о нем очень мало, штука довольно неоднозначная. Скажем, WhatsApp используют его, но они и умеют его правильно готовить.
понятно, чудес не бывает — пересылок данных не избежать, наверное внутренняя сеть очень скоростная у них
Там не только внутренняя сеть, там еще по возможности оптимизированное взаимодействие erlang-нод. При использовании erlang distribution «в лоб», без хитростей, уже 100 нод будет проблемой.
У WhatsApp, если мне не изменяет память, что-то вроде 11000 ядер на порядка 500 машин. Не помню точные числа, но о сравнимых по масштабу инсталляциях я больше не знаю.
У WhatsApp, если мне не изменяет память, что-то вроде 11000 ядер на порядка 500 машин. Не помню точные числа, но о сравнимых по масштабу инсталляциях я больше не знаю.
А еще я допустил терминологическую неточность — вместо
«в ets — in-memory-таблице, позволяющей доступ из нескольких процессов»
должно быть написано
«в ets — in-memory-таблице, позволяющей доступ из нескольких акторов». Первая формулировка, кажется, может ввести читателя в заблуждение.
«в ets — in-memory-таблице, позволяющей доступ из нескольких процессов»
должно быть написано
«в ets — in-memory-таблице, позволяющей доступ из нескольких акторов». Первая формулировка, кажется, может ввести читателя в заблуждение.
В языках Python/Ruby/PHP обработчик http-запроса имеет свою область памяти, которая актуальна только на время обработки запроса. Если нужно хранить какие-то данные между запросами, то приходится обращаться к внешним сервисам, таким как Radis.
В Erlang обработчику доступна вся память узла (не напрямую, конечно), и хранилище данных можно организовать прямо внутри сервиса. Например, с помощью ets-таблиц.
В Erlang обработчику доступна вся память узла (не напрямую, конечно), и хранилище данных можно организовать прямо внутри сервиса. Например, с помощью ets-таблиц.
Насчет конфигов — тот же ejabberd переехал со стандартных эрланговых туплов на yaml. Как раз при переезде bigworld-проекта на новый сервер под jessie столкнулся с этим.
Очень мало библиотек у ирла, а те, что есть, часто заброшены даже не дойдя до стабильной версии. При этом довольно много дублирующихся либ, у каждой из которых есть свои сильные и слабые стороны, о которых надо знать, вообщем боль )
Но уже как год пишу на нем каждый день и постепенно начал получать удовольствие, — всем рекомендую, язык совершенно напрасно обделен вниманием.
Но уже как год пишу на нем каждый день и постепенно начал получать удовольствие, — всем рекомендую, язык совершенно напрасно обделен вниманием.
К минусам, но не самого языка, а экосистемы вокруг него, стоит добавить узкий рынок вакансий в контексте веба. Я даже помню, как в начале появлялась вакансия (в том же яндексе, если не ошибаюсь) и все сразу такие "ооо, требуется erlang программист".
У нас часто бывают вакансии для Erlang-разработчиков) Можете мониторить http://wargaming.com/ru/careers/vacancies/ или отправить ссылку на резюме/резюме в личку. Добавим в базу, если будут подходящие места — свяжемся.
они даже в статье писали. нет смысла пользовать эрланг для веба — т.к. у него нет никаки преимущесв перед другими широко используемыми системами где более дешевые, заменямые человекоресурсы и богатство инструментов и тулов.
удел erlang — бекенды для игровых серверов, чатов и подобных коммуникационных систем.
удел erlang — бекенды для игровых серверов, чатов и подобных коммуникационных систем.
Кто они? :)
Мы (Wargaming) видим смысл в том, чтобы использовать эрланг для веба. При желании этот смысл можно посчитать в человекочасах разработки или деньгах. Один и тот же веб-сервис можно построить на Python, а можно на Erlang. И после определенного уровня нагрузки, которую должен держать сервис, второй вариант выходит дешевле в человекочасах и деньгах.
Мы (Wargaming) видим смысл в том, чтобы использовать эрланг для веба. При желании этот смысл можно посчитать в человекочасах разработки или деньгах. Один и тот же веб-сервис можно построить на Python, а можно на Erlang. И после определенного уровня нагрузки, которую должен держать сервис, второй вариант выходит дешевле в человекочасах и деньгах.
вы в своем коменте сейчас сами речь ведете об web заточеном под определенный круг задач.
и много компаний пишут веб на эрланге? нет
почему? если все так "просто" и "дешево"?
и много компаний пишут веб на эрланге? нет
почему? если все так "просто" и "дешево"?
узкий рынок вакансий в контексте веба
это не минус erlang а общепринятые требования для данного сектора
в ерланге строк нету — собрались комон веб приложения писать. ага.
В Wargaming используется микросервисная архитектура, где разные сервисы взаимодействуют между собой как по HTTP-протоколу, так и по AMQP.
Веб тоже разный бывает. Бывает в монолитном виде "отвалидировать форму, сходить в БД, что-то посчитать, провернуть какие-то бизнес-операции, выплюнуть HTML-ку с данными и менюшками". Обычно так на ранних стадиях проекта работает.
А когда к проекту начинают прикручивать платёжную систему, рассылку нотификаций на различные устройства, множество методов авторизации, мобильную версию, API, мобильные приложения и пр, то эти задачи реализовываются уже в отдельных приложениях-микросервисах, которые принимают на вход JSON, возвращают JSON и всё. После этого "веб" превращается в тонкую прослойку — пользовательский интерфейс, который хоть на PHP можно писать. Валидатор форм и шаблонизатор.
Вся остальная "мякота" именно в этих микросервисах.
В эрланге нет строк но есть бинари, и, что более важно, io-списки. Последние таки просто созданы для эффективной шаблонизации и всякого такого.
Erlang очень хорош для современного веба где есть realtime взаимодействие с пользователем и много сервисов вокруг проекта. Для обычных сайтов хватало и традиционных решений.
«Мыши плакали, кололись, но продолжали грызть кактус»
Зачем нужен Twisted, когда есть Tornado? Простой как три палки, поддерживаемый и шустрый.
Интересная статья, редкий отзыв с живым впечатлением!
Для разработки многопоточных приложений советую попробовать еще язык Go. Его синтаксис ближе всего к Pyton, так что вашим разработчикам не придется напрягаться.
Если брать пример со строками — то ка раз в Go отличная работа со строками, все нативно обрабатывается в UTF8, можете переменные на китайском или русском в коде писать, и как угодно обрабатывать строки без боли.
Я не знаю как будет восприниматься Go после Pyton, но во всяком случае в каждом отзыве пишут что скорость разработки в 10 раз быстрее чем на C/C++. Это действительно очень простой язык и комфортный.
Я бы его сегодня сделал учебным в школах.
Для разработки многопоточных приложений советую попробовать еще язык Go. Его синтаксис ближе всего к Pyton, так что вашим разработчикам не придется напрягаться.
Если брать пример со строками — то ка раз в Go отличная работа со строками, все нативно обрабатывается в UTF8, можете переменные на китайском или русском в коде писать, и как угодно обрабатывать строки без боли.
Я не знаю как будет восприниматься Go после Pyton, но во всяком случае в каждом отзыве пишут что скорость разработки в 10 раз быстрее чем на C/C++. Это действительно очень простой язык и комфортный.
Я бы его сегодня сделал учебным в школах.
Давно не был на хабре.
Тут больше не принято уважать чужое мнение или это топик Go-хейтеров?
Тут больше не принято уважать чужое мнение или это топик Go-хейтеров?
Go здесь не причем. Ваш комментарий как листовка в почтовом ящике. Пользы никакой, буллшитная реклама. Только выкинуть нельзя.
Тоже о комментарии.
Тоже о комментарии.
Несколько месяцев назад я решил изучить какой нибудь перспективный язык для сетевых вещей. Я выбирал между Javascript/Node.js и Erlang. В итоге остановился… на Go.
Я перечитал еще раз свой комментарий. Могу заново написать каждую строчку и доказать каждое утверждение не только ссылками но и личным опытом. Но не буду!
Вместо этого я выпущу код из презентации релиза Go 1.6:
Просто напишите код, который запустит n = 100 конкурентных процессов и инкрементирует единственную переменную в разделяемом ассоциативном массиве.
Хотелось бы увидеть код Erlang, Python, ну быть может даже на C++ И, да, никаких библиотек, только системные. Это вызов!
Посмотрим, считается ли булшитом и код на сегодняшнем Хабре.
Я перечитал еще раз свой комментарий. Могу заново написать каждую строчку и доказать каждое утверждение не только ссылками но и личным опытом. Но не буду!
Вместо этого я выпущу код из презентации релиза Go 1.6:
func count(n int) {
var wg sync.WaitGroup
wg.Add(n)
m := map[int]int{}
var mu sync.Mutex
for i := 1; i <= n; i++ {
go func(i int) {
for j := 0; j < i; j++ {
mu.Lock()
m[i]++
mu.Unlock()
}
wg.Done()
}(i)
}
wg.Wait()
}
Просто напишите код, который запустит n = 100 конкурентных процессов и инкрементирует единственную переменную в разделяемом ассоциативном массиве.
Хотелось бы увидеть код Erlang, Python, ну быть может даже на C++ И, да, никаких библиотек, только системные. Это вызов!
Посмотрим, считается ли булшитом и код на сегодняшнем Хабре.
ets:new(test, [ named_table, public ]),
[ spawn(fun() -> ets:update_counter(test, key, 1, { key, 0 }) end) || _X <- lists:seq(1, 100) ].
познакомьте что ли человека с языком атомарных условных апдейтов счетчиков.
Спасибо, не надо меня знакомить. Не убедили меня ни в простоте ни красоте Erlang. Но это неважно, главное что бы сами в это верили, а другой взгляд на вопрос всегда можно заминусовать до невидимости, здорово же!
Зато я познакомился с go хейтерами, узнал чего больше всего на свете боятся Эрлангеры и как функционирует сегодняшний хабр.
Это был очень полезный опыт, спасибо друзья!
Зато я познакомился с go хейтерами, узнал чего больше всего на свете боятся Эрлангеры и как функционирует сегодняшний хабр.
Это был очень полезный опыт, спасибо друзья!
Давайте жить дружно) Да и зачем в Erlang топике сравнивать его с императивным языком, да ещё и с компилируемым системным? Если вам уж так хочется найти его слабое место, то его и искать не надо, в любом числодроблении он пролетает и для майнинга точно не подходит)
Увы, вы сделали неправильные выводы. Это не go-хейтинг.
Отвлекитесь немного от своего любимого дамского пукальника
и ответьте себе на следующие вопросы:
Потом перечитайте свой комментарий и задайте себе последний вопрос,
что вам было бы лучше:
Отвлекитесь немного от своего любимого дамского пукальника
и ответьте себе на следующие вопросы:
- какова тематика статьи?
- каков, по вашему мнению, профессиональный уровень автора
и объем его профессионального опыта? - сколько лет Go и является ли сообщение о нем благой вестью,
которую вам с утра сообщил горящий терновый куст? - насколько сильно разработчики таких проектов придают значение
комфортности обработки строк при выборе инструментария?
Потом перечитайте свой комментарий и задайте себе последний вопрос,
что вам было бы лучше:
- советовать абы что, как вы сделали;
- промолчать;
- пойти на Go-форум, спросить мнение тамошних гуру(не фанатов) о статье и вернуться
с вопросом?
Давайте я отвечу вам на вопросы
Тематика статьи — мы решили попробовать что-то новенькое. И вот цитата автора
Не будь этой цитаты, никто бы не упомянул Go ни разу! Я в этом уверен, за себя ручаюсь на 100%.
Я начал свой пост с благодарности автору за статью. Достаточно для оценки авторитета?
Сколько лет Эрлангу и является ли сообщение о нем благой вестью?
Не знаю какие мысли в голове у разработчиков, лучше наверно их спросить, но мне кажется одна из причин интереса к Go, это прежде всего простота и красота кода, которая в результате повышает продуктивность. Это не один и не два и не три отзыва от разработчиков на других языках. Erlang совершенно точно ценят не за простоту, вспомним хотя бы парадигму функционального программирования. Самый лучший совет от гуру Эрланга звучал так — если вы не понимаете заечем вам нужен Эрланг, значит он вам не нужен.
Мне было бы лучше никогда не читать эту статью и не знать о склочности Erlang комьюнити. Я обратил внимание что хабре чрезвычайно мало информации о Go, статьи старые переводов мало. Почти всю информацию о Go я получаю из англоязычных ресурсов, немного с пары русскоязычных сайтов.
Признаюсь, что у меня даже проскочила мысль немного восполнить этот пробел и написать что то для этой аудитории. Однако, благодаря, вашей трогательной заботе, я сохранил кучу времени и нервов, а хабр не получил какой то статьи.
Спасибо вам и удачи!
какова тематика статьи?
Тематика статьи — мы решили попробовать что-то новенькое. И вот цитата автора
Архитекторы не против попробовать и другие варианты: язык Go, один из JVM-языков, еще что-то – но пока желающие нашлись только на Elixir, и об этом ниже.
Не будь этой цитаты, никто бы не упомянул Go ни разу! Я в этом уверен, за себя ручаюсь на 100%.
каков, по вашему мнению, профессиональный уровень автора
и объем его профессионального опыта?
Я начал свой пост с благодарности автору за статью. Достаточно для оценки авторитета?
сколько лет Go и является ли сообщение о нем благой вестью,
которую вам с утра сообщил горящий терновый куст?
Сколько лет Эрлангу и является ли сообщение о нем благой вестью?
- Демагогия.
насколько сильно разработчики таких проектов придают значение
комфортности обработки строк при выборе инструментария?
Не знаю какие мысли в голове у разработчиков, лучше наверно их спросить, но мне кажется одна из причин интереса к Go, это прежде всего простота и красота кода, которая в результате повышает продуктивность. Это не один и не два и не три отзыва от разработчиков на других языках. Erlang совершенно точно ценят не за простоту, вспомним хотя бы парадигму функционального программирования. Самый лучший совет от гуру Эрланга звучал так — если вы не понимаете заечем вам нужен Эрланг, значит он вам не нужен.
Потом перечитайте свой комментарий и задайте себе последний вопрос,
что вам было бы лучше:
Мне было бы лучше никогда не читать эту статью и не знать о склочности Erlang комьюнити. Я обратил внимание что хабре чрезвычайно мало информации о Go, статьи старые переводов мало. Почти всю информацию о Go я получаю из англоязычных ресурсов, немного с пары русскоязычных сайтов.
Признаюсь, что у меня даже проскочила мысль немного восполнить этот пробел и написать что то для этой аудитории. Однако, благодаря, вашей трогательной заботе, я сохранил кучу времени и нервов, а хабр не получил какой то статьи.
Спасибо вам и удачи!
> мы решили попробовать что-то новенькое.
Пару лет назад решили, а сейчас уже разговор идет о результатах. Эксперимент уже удался, советы не особо актуальны.
> простота и красота кода, которая в результате повышает продуктивность
Маркетинговый буллщит.
> Erlang совершенно точно ценят не за простоту,
> вспомним хотя бы парадигму функционального программирования.
Erlang не является функциональным ЯП, абсолютно точно. Тут есть пара комментариев, по которым заметна ошибочность и вредность этого подхода.
HOF, иммутабельность и pattern matching уже далеко распространились за пределы ФП.
И да, в посте отмечено, что Erlang — простой.
> склочности Erlang комьюнити
Нет никакой склочности. Вы приходите к людям, которые знают, что делают, и пытаетесь продать им что-то ненужное. Какой вы реакции ждали?
> хабр не получил какой то статьи
Замечательно. На хабре уже более чем достаточно go-фанбоев, хватит.
Позволю себе излишне обобщить — все присутствующие знают и Erlang, и Go, и прекрасно знают, что и когда применять. И то, что если нужно делать сетевые сервисы в масштабах Wargaming, выигрывает именно Erlang, при всех его недостатках, все тоже знают.
Упырьте мел, тут нет фанбоев, это же не пост про Go.
Пару лет назад решили, а сейчас уже разговор идет о результатах. Эксперимент уже удался, советы не особо актуальны.
> простота и красота кода, которая в результате повышает продуктивность
Маркетинговый буллщит.
> Erlang совершенно точно ценят не за простоту,
> вспомним хотя бы парадигму функционального программирования.
Erlang не является функциональным ЯП, абсолютно точно. Тут есть пара комментариев, по которым заметна ошибочность и вредность этого подхода.
HOF, иммутабельность и pattern matching уже далеко распространились за пределы ФП.
И да, в посте отмечено, что Erlang — простой.
> склочности Erlang комьюнити
Нет никакой склочности. Вы приходите к людям, которые знают, что делают, и пытаетесь продать им что-то ненужное. Какой вы реакции ждали?
> хабр не получил какой то статьи
Замечательно. На хабре уже более чем достаточно go-фанбоев, хватит.
Позволю себе излишне обобщить — все присутствующие знают и Erlang, и Go, и прекрасно знают, что и когда применять. И то, что если нужно делать сетевые сервисы в масштабах Wargaming, выигрывает именно Erlang, при всех его недостатках, все тоже знают.
Упырьте мел, тут нет фанбоев, это же не пост про Go.
Я просил обновление ассоциативного массива, вы дали пример с atomic update. Просто ответьте пожалуйста, поддерживает ли storage etc ассоциативные массивы, они же hash они же map. Вы знаете ответ сразу, а мне для этого весь документ читать.
И да, ваш пример на Go будет выглядеть так:
И да, ваш пример на Go будет выглядеть так:
func main() {
var ops uint64 = 0
for i := 0; i < 100; i++ {
go func() {
for {
atomic.AddUint64(&ops, 1)
runtime.Gosched()
}
}()
}
time.Sleep(time.Second)
opsFinal := atomic.LoadUint64(&ops)
в ирле нету массивов, есть списки, хеши тоже есть. ets поддерживает любые значения
Попробую ответить, абстрагируясь от того, что к Erlang испытываю теплые чувства, добавив к этому тот факт, что по работе его не использую (пока). И еще тот факт, что Go мне по статьям, что я видел, не очень понравился, в контексте тех знаний и возможностей, что есть по Erlang. Для бОльшей чистоты эксперимента, мы обсудили ваш вопрос с моим товарищем, который не знает ни Go ни Erlang (мы вместе пишем на Verilog).
Если посмотреть совсем со стороны, то из вашего примера кода, даже можно что-то понять, человеку, который на Go никогда не писал. Вот есть мутекс. Вот фанка, в ней глобальная map, потом в цикле, очевидно, идет запуск функций, которые работают параллельно, которые перед запуском лочат мутекс. За гранью понимания остаются знания о том, что такое мутекс, как он работает в Go, что такое waitGroup, зачем в него добавляется add, и для чего там wg.Done, wg.Wait. Если поглядеть дальше, в код atomic update, то вопросов у меня появляется еще больше: про addUint, про Goshed, зачем там time.Sleep, что такое opsFinal.
Из примера на Erlang, подозреваю, непосвященному понятно совсем мало. Врядли понятно, что такое lists:seq, а если и так, то дальше там List Comprehensions, не забываем про ETS. Но, к слову, это все стандартные возможности и общепринятый подход к решению. Мнение моего товарища дословно звучало так: "один кирпичем гвоздь забил другой микроскопом". Очевидно, тут Go даже выигрывает по понятности кода.
По поводу "теплого приема", попробую объяснить возможную причину. Произошло именно "Вы приходите к людям, которые знают, что делают, и пытаетесь продать им что-то ненужное." А именно, в Erlang не возникает такой задачи, как менять общую память с помощью 100 процессов. Это одна из важнейших концепций — избавление от глобалстейт, глобальных ресурсов, как причины возникновения возможных проблем. Поэтому, предложить эрлангисту решить задачу так, как вы предлагаетет — это именно "пытаться продать что-то ненужное". Предложить решить задачу на эрланге таким способом, который в концепциях ерланга считается не верным.
В конечном итоге, без глобальных ресурсов не обойтись. Ваша задача по сути является задачей создания общего хранилища для N процессов. Я не буду писать код, опишу суть. Для хранения map будет запущен процесс-сервер, в котором она и будет храниться. Если слово "сервер" напрягает, назовите это "микросервер" или "микросервис", процесс-хранилище. Все изменения map будут происходить через отправку сообщений процессу-хранилищу от N процессов.
У меня к вам вопрос — ведь функция go выполняется, как "зеленый"/софтпроцесс или это процесс на аппаратном уровне?
Не зависимо от этого, решение на Go и на Erlang в принципе выполнит одно и то же: процессы по очереди поменяют значение мапа.
На Go получится 100 процессов запустилось, первый из них, кому шедулер даст — залочит мутекс. Остальные будут ждать. Произойдет изменение данных, анлок. После этого тот какой-то (скорее всего вообще неведомо какой) из оставшихся 99 процессов, по команде шедулера продолжит работу, залочит мап, Остальные будут ждать. И так далее.
На Erlang получится 100 процессов запустилось и отправило сообщение процессу-хранилищу об изменении данных. Все сообщения попадут в очередь принятых сообщений процесса-хранилища. Я думаю, что они в этой очереди будут именно в порядке запуска 100 процессов, и очередность будет соблюдена (без всяких redis). Возможно, в этой задаче это не имеет значения, но и сама задача тоже слегка оторвана от реальности. Дальше, допустим, процесс не просто должен был поменять что-то в мапе, как сейчас +1, а должен получить результат, либо что-то рассчитать от того значения, которое там есть сейчас. Иначе бы решение было как раз +1 и в каком оно там порядке — вообще без разницы. Короче, предположим, что каждый процесс из 100, должен получить какой-то результат. Поэтому, сразу после отправки сообщения, он ждет сообщение-ответ от процесса-хранилища с результатом, и пока сообщений-ответов нет — процесс спит. И так со всеми 100 процессами: все они в одном порядке запустятся, отправят, уснут, и в том же порядке получат ответы, что-то с ними сделают и сдохнут. С тем же успехом можно запустить не 100, а 100 000 процессов и замерять время на получение результата.
Суть на самом деле не меняется: в один момент времени, один процесс меняет данные. Но инструменты для этого получаются разные. В ерланге очень многое решается через процессы и сообщения. Возможно, что прелесть как раз в том, что для решения задач используется меньше инструментов. Именно это нагромождение понятий, терминов и методов меня отпугнуло от Go по тем статьям, что я увидел. Очень буду рад ошибаться. По ерлангу я изучил очень много материалов, видео и книг и мне потребовалось на много больше времени, чем две недели, чтобы это все структурировалось в голове. И теперь какие-то материалы я мог бы порекомендовать изучить в первую очередь.
Может быть вы посоветуете материал по Go, который стоит изучить в первую очередь?
Хоть это и прозвучит плохо, но это похоже на правду. Во всяком случае, я соглашусь с таким мнением. Но мое согласие врядли кого-то в чем-то убедит. Однажды я задал вопрос, стоит ли снимать семейное фото на Ч/Б пленку и вообще стоит ли на нее снимать? Те, кто на нее снимают — знают ответ на вопрос, для чего они это делают. А ведь есть еще снимающие на форматные камеры и пластинки с мокрым коллодием. По моему личному опыту, я знал, для чего мне нужен ерланг еще до того, как начал его изучать. Не соглашусь с тем, что для изучения ерланг нужно две недели. Может и так, но перед этим надо несколько лет подолбиться головой, применяя другие технологии, понять их ограничения. Поглядеть изнутри на проект, где серверная логика состоит из триггеров postgres, и питон с помощью redis и memcache дергает все это дело, пытаясь правильно работать с сокетами через epoll и все это оседает в riak, с бессмысленной и беспощадной работой потом на клиенте по выстроению сообщений по таймлайну. Или краем глаза поглядеть, как парни делают «суперсовременную облачную платформу» для бухгалтери, где в качестве бекенда у них си++ и раббитMQ ведь нативного MQ си нет(?), но внезапно обновилась версия бустио, после чего их костыли с таймерами, посылающие периодические пакеты в сокет, чтобы он не протух, перестали работать, и теперь срочно надо обновление библиотеки откатывать, собирать новый пакет под линукс, накатывать на серверы и так далее. Ну зато си знают хорошо, спору нет. Задаться вопросом, а сколько процессов должно быть у сервера c++ на 10к/100k/1M соединений, сколько раз в неделю его надо ребутить из за течки… Вот после такого ада, ерланг мне представляется действительно хорошим инструментов. Своей самодостаточностью, своими возможностями для создания надежных приложений, распределенных приложений, обновляемых на ходу приложений, своей ВМ. Я уже давно слышал о том, что и в си++ появились или появятся «зеленые процессы», рядом пишут, что иммутабельность и паттерн матчинг есть в других языках и это замечательно. Хорошо, когда идет развитие и есть выбор.
Если посмотреть совсем со стороны, то из вашего примера кода, даже можно что-то понять, человеку, который на Go никогда не писал. Вот есть мутекс. Вот фанка, в ней глобальная map, потом в цикле, очевидно, идет запуск функций, которые работают параллельно, которые перед запуском лочат мутекс. За гранью понимания остаются знания о том, что такое мутекс, как он работает в Go, что такое waitGroup, зачем в него добавляется add, и для чего там wg.Done, wg.Wait. Если поглядеть дальше, в код atomic update, то вопросов у меня появляется еще больше: про addUint, про Goshed, зачем там time.Sleep, что такое opsFinal.
Из примера на Erlang, подозреваю, непосвященному понятно совсем мало. Врядли понятно, что такое lists:seq, а если и так, то дальше там List Comprehensions, не забываем про ETS. Но, к слову, это все стандартные возможности и общепринятый подход к решению. Мнение моего товарища дословно звучало так: "один кирпичем гвоздь забил другой микроскопом". Очевидно, тут Go даже выигрывает по понятности кода.
По поводу "теплого приема", попробую объяснить возможную причину. Произошло именно "Вы приходите к людям, которые знают, что делают, и пытаетесь продать им что-то ненужное." А именно, в Erlang не возникает такой задачи, как менять общую память с помощью 100 процессов. Это одна из важнейших концепций — избавление от глобалстейт, глобальных ресурсов, как причины возникновения возможных проблем. Поэтому, предложить эрлангисту решить задачу так, как вы предлагаетет — это именно "пытаться продать что-то ненужное". Предложить решить задачу на эрланге таким способом, который в концепциях ерланга считается не верным.
В конечном итоге, без глобальных ресурсов не обойтись. Ваша задача по сути является задачей создания общего хранилища для N процессов. Я не буду писать код, опишу суть. Для хранения map будет запущен процесс-сервер, в котором она и будет храниться. Если слово "сервер" напрягает, назовите это "микросервер" или "микросервис", процесс-хранилище. Все изменения map будут происходить через отправку сообщений процессу-хранилищу от N процессов.
У меня к вам вопрос — ведь функция go выполняется, как "зеленый"/софтпроцесс или это процесс на аппаратном уровне?
Не зависимо от этого, решение на Go и на Erlang в принципе выполнит одно и то же: процессы по очереди поменяют значение мапа.
На Go получится 100 процессов запустилось, первый из них, кому шедулер даст — залочит мутекс. Остальные будут ждать. Произойдет изменение данных, анлок. После этого тот какой-то (скорее всего вообще неведомо какой) из оставшихся 99 процессов, по команде шедулера продолжит работу, залочит мап, Остальные будут ждать. И так далее.
На Erlang получится 100 процессов запустилось и отправило сообщение процессу-хранилищу об изменении данных. Все сообщения попадут в очередь принятых сообщений процесса-хранилища. Я думаю, что они в этой очереди будут именно в порядке запуска 100 процессов, и очередность будет соблюдена (без всяких redis). Возможно, в этой задаче это не имеет значения, но и сама задача тоже слегка оторвана от реальности. Дальше, допустим, процесс не просто должен был поменять что-то в мапе, как сейчас +1, а должен получить результат, либо что-то рассчитать от того значения, которое там есть сейчас. Иначе бы решение было как раз +1 и в каком оно там порядке — вообще без разницы. Короче, предположим, что каждый процесс из 100, должен получить какой-то результат. Поэтому, сразу после отправки сообщения, он ждет сообщение-ответ от процесса-хранилища с результатом, и пока сообщений-ответов нет — процесс спит. И так со всеми 100 процессами: все они в одном порядке запустятся, отправят, уснут, и в том же порядке получат ответы, что-то с ними сделают и сдохнут. С тем же успехом можно запустить не 100, а 100 000 процессов и замерять время на получение результата.
Суть на самом деле не меняется: в один момент времени, один процесс меняет данные. Но инструменты для этого получаются разные. В ерланге очень многое решается через процессы и сообщения. Возможно, что прелесть как раз в том, что для решения задач используется меньше инструментов. Именно это нагромождение понятий, терминов и методов меня отпугнуло от Go по тем статьям, что я увидел. Очень буду рад ошибаться. По ерлангу я изучил очень много материалов, видео и книг и мне потребовалось на много больше времени, чем две недели, чтобы это все структурировалось в голове. И теперь какие-то материалы я мог бы порекомендовать изучить в первую очередь.
Может быть вы посоветуете материал по Go, который стоит изучить в первую очередь?
Просто ответьте пожалуйста, поддерживает ли storage etc ассоциативные массивы, они же hash они же mapЕсть с 17й версии стандарный модуль maps. Ассоциативный, в качестве ключа и значения может быть что угодно: число, список/строка, кортеж, бинари. После появления maps у себя выкинул много кода, потому что процесс, к примеру, разбора и получения значений json стал на много проще.
Самый лучший совет от гуру Эрланга звучал так — если вы не понимаете заечем вам нужен Эрланг, значит он вам не нужен.
Хоть это и прозвучит плохо, но это похоже на правду. Во всяком случае, я соглашусь с таким мнением. Но мое согласие врядли кого-то в чем-то убедит. Однажды я задал вопрос, стоит ли снимать семейное фото на Ч/Б пленку и вообще стоит ли на нее снимать? Те, кто на нее снимают — знают ответ на вопрос, для чего они это делают. А ведь есть еще снимающие на форматные камеры и пластинки с мокрым коллодием. По моему личному опыту, я знал, для чего мне нужен ерланг еще до того, как начал его изучать. Не соглашусь с тем, что для изучения ерланг нужно две недели. Может и так, но перед этим надо несколько лет подолбиться головой, применяя другие технологии, понять их ограничения. Поглядеть изнутри на проект, где серверная логика состоит из триггеров postgres, и питон с помощью redis и memcache дергает все это дело, пытаясь правильно работать с сокетами через epoll и все это оседает в riak, с бессмысленной и беспощадной работой потом на клиенте по выстроению сообщений по таймлайну. Или краем глаза поглядеть, как парни делают «суперсовременную облачную платформу» для бухгалтери, где в качестве бекенда у них си++ и раббитMQ ведь нативного MQ си нет(?), но внезапно обновилась версия бустио, после чего их костыли с таймерами, посылающие периодические пакеты в сокет, чтобы он не протух, перестали работать, и теперь срочно надо обновление библиотеки откатывать, собирать новый пакет под линукс, накатывать на серверы и так далее. Ну зато си знают хорошо, спору нет. Задаться вопросом, а сколько процессов должно быть у сервера c++ на 10к/100k/1M соединений, сколько раз в неделю его надо ребутить из за течки… Вот после такого ада, ерланг мне представляется действительно хорошим инструментов. Своей самодостаточностью, своими возможностями для создания надежных приложений, распределенных приложений, обновляемых на ходу приложений, своей ВМ. Я уже давно слышал о том, что и в си++ появились или появятся «зеленые процессы», рядом пишут, что иммутабельность и паттерн матчинг есть в других языках и это замечательно. Хорошо, когда идет развитие и есть выбор.
… Я обратил внимание что хабре чрезвычайно мало информации о Go, статьи старые переводов мало. Почти всю информацию о Go я получаю из англоязычных ресурсов, немного с пары русскоязычных сайтов.А вот это зря. Я считаю, что делиться полученной и наработанной информацией это благое дело. Тем более, есть пробел. Нужно заполнять пустоту. Представьте, вы переработали кучу информации, потратили на это колоссальное количество времени. Написали статью и тем самым сэкономили кучу времени для меня. Подарили не только информацию, но и время — невосполнимый ресурс. Подарили лишний час с родными ну или на худой конец лишний час в рублях на работе. Возникла мысль написать статью — напишите. Или комментарии могут вас так легко переубедить? ;)
Признаюсь, что у меня даже проскочила мысль немного восполнить этот пробел и написать что то для этой аудитории. Однако, благодаря, вашей трогательной заботе, я сохранил кучу времени и нервов, а хабр не получил какой то статьи...
Отвечу на ваши вопросы
Гоурутины — наиболее легковестный процесс из всех других альтернативых реализаций многопоточности. Не силен в деталях, но при запуске горутины выделяется 4 кб памяти и переключаются несколько регистров. Сравните с полным переключением контекста или вообще с потоками операционной системы. В результате декларируется возможность на сервере запускать легко до 100 тысяч горутин, лишь бы памяти хватило.
Все верно. Вопрос в том что начиная с версии 1.6 это не только работает быстро, но еще и компилятор выдаст предупреждение, если не дай бог программист не сделает блокировку разделяемые данные. Причем речь именно о хеш-масивах, с обычными массивами даже этого не потребуется, операция будет атомарна.
Основная фича Go — каналы, она именно так работает, как вы рассказали на примере Эрланга, я подозреваю что даже синтаксис <- и -> от туда взят.
не буду объяснять проще дать ссылку на туториал: http://golang-book.ru/chapter-10-concurrency.html
Потратьте один вечер на эту книжку: http://golang-book.ru/
Если будет интересно, я дам в личку еще ссылок и одну полноценную книгу.
Если резюмировать про многопоточность, то в Go есть самые легкие сопроцессы, три вида работы с данными в многозадачности — каналы, мутексы, и атомарные апдейты. Кстати и системные треды вроде есть, просто они никому не нужны. Так же Го — это компилятор, а не виртуальная машина как Эрланг. И что важно, это императивный язык программирования, который понятен с первой секунды. В отличие скажем он парадигмы функционального программирования, к которой люди приходят с багажом знаний.
У меня к вам вопрос — ведь функция go выполняется, как "зеленый"/софтпроцесс или это процесс на аппаратном уровне?
Гоурутины — наиболее легковестный процесс из всех других альтернативых реализаций многопоточности. Не силен в деталях, но при запуске горутины выделяется 4 кб памяти и переключаются несколько регистров. Сравните с полным переключением контекста или вообще с потоками операционной системы. В результате декларируется возможность на сервере запускать легко до 100 тысяч горутин, лишь бы памяти хватило.
На Go получится 100 процессов запустилось, первый из них, кому шедулер даст — залочит мутекс. Остальные будут ждать. Произойдет изменение данных, анлок. После этого тот какой-то (скорее всего вообще неведомо какой) из оставшихся 99 процессов, по команде шедулера продолжит работу, залочит мап, Остальные будут ждать. И так далее.
Все верно. Вопрос в том что начиная с версии 1.6 это не только работает быстро, но еще и компилятор выдаст предупреждение, если не дай бог программист не сделает блокировку разделяемые данные. Причем речь именно о хеш-масивах, с обычными массивами даже этого не потребуется, операция будет атомарна.
На Erlang получится 100 процессов запустилось и отправило сообщение процессу-хранилищу об изменении данных. Все сообщения попадут в очередь принятых сообщений процесса-хранилища.
Основная фича Go — каналы, она именно так работает, как вы рассказали на примере Эрланга, я подозреваю что даже синтаксис <- и -> от туда взят.
не буду объяснять проще дать ссылку на туториал: http://golang-book.ru/chapter-10-concurrency.html
Может быть вы посоветуете материал по Go, который стоит изучить в первую очередь?
Потратьте один вечер на эту книжку: http://golang-book.ru/
Если будет интересно, я дам в личку еще ссылок и одну полноценную книгу.
Если резюмировать про многопоточность, то в Go есть самые легкие сопроцессы, три вида работы с данными в многозадачности — каналы, мутексы, и атомарные апдейты. Кстати и системные треды вроде есть, просто они никому не нужны. Так же Го — это компилятор, а не виртуальная машина как Эрланг. И что важно, это императивный язык программирования, который понятен с первой секунды. В отличие скажем он парадигмы функционального программирования, к которой люди приходят с багажом знаний.
Вот вам еще для поднятия эрудиции. Много чего в мире существует.
m <- atomically $ newTVar IntMap.empty
forM_ [0..n] $ \i ->
void . forkIO . atomically $ modifyTVar' m (inc i)
where
inc i m =
foldl' (\acc j ->
IntMap.insertWith upd j 0 acc) m [0..i]
upd _ o = o + 1
Erlang успешно использую уже лет 10. Для своих задач исключительно хорош, практически уникален.
Небольшой пример из последних проектов — распределенный краулер BitTorrent DHT сети.
40 тысяч DHT-нод на трех машинах, 200 тыс запросов в секунду.
Без возможностей Erlang по runtime интроспекции и трассировке процессов пилил бы год-два,
так как реальное поведение мировой DHTсети torrent-клиентов оказалось весьма далеким от
первоначального представления.
Erlang позволил запустить проект за полтора месяца.
Итог — накопано 20 млн уникальных торрентов за два года, не считая другой полезной информации
о состоянии сети.
Небольшой пример из последних проектов — распределенный краулер BitTorrent DHT сети.
40 тысяч DHT-нод на трех машинах, 200 тыс запросов в секунду.
Без возможностей Erlang по runtime интроспекции и трассировке процессов пилил бы год-два,
так как реальное поведение мировой DHTсети torrent-клиентов оказалось весьма далеким от
первоначального представления.
Erlang позволил запустить проект за полтора месяца.
Итог — накопано 20 млн уникальных торрентов за два года, не считая другой полезной информации
о состоянии сети.
Видео доклада с митапа func (by)
Помню, мне было сложно войти в OTP когда начинал изучение..., а программку с динамическими процессами написал за дня два-три… Я еще циклы долго искал :)
Спасибо за обзор, было очень интересно (часто писал/пишу на Python/Tornado/Pylons). Как обстоят дела с асинхронностью в Erlang?
Есть ли возможность писать явно асинхронный код ака asynс из Python 3.5?
Есть ли возможность писать явно асинхронный код ака asynс из Python 3.5?
Sign up to leave a comment.
Erlang в Wargaming