С целью увеличить счетчик статей про "редкий" язык Erlang еще на одну, расскажем как на коленке собрать Erlang кластер и запустить на нем распараллеленное вычисление.  Для понимания происходящего, читателю возможно понадобится знание основ Erlang (без OTP). Которые, кстати, можно получить не отходя от кассы не уходя из уютного Хабра, прямо тут: Но, не будем умничать раньше времени и сначала сделаем... Как мы сейчас понимаем, по мере развития IT-индустрии совершенно разные языки программирования находят свое применение. Не стал исключением и язык Erlang, изначально разрабатывавшийся как язык для отказоустойчивых систем, но завоевавший свою нишу в нашем мире распределенных многопроцессорных систем благодаря: И при этом оставаясь: Перечислим компании и проекты, использующих Erlang в production: Не будем скрывать от читателя, что, и на наш взгляд, у языка есть слабые места, о которые хорошо описаны у других авторов, например: Erlang в Wargaming Ну а теперь давайте по-программируем, и напишем функцию, которая делает... Сигнатуру этой функции сделаем похожей на lists:map: map(Fn, Items, WorkersN, Timeout) -> {ok, [FnResult]} | {error, timeout}, throws {'EXIT', Reason}, где: Реализация функции: Вот основные моменты в коде: Сигнатура этой функции: map_loop(Context) -> [FnResult] Реализация: Пройдемся по реализации: Пробежимся по приватным функциям, которые мы тут использовали: Полный листинг функции можно посмотреть на GitHub: тут Теперь чуть потестируем нашу функцию через Erlang REPL. 1) Запустим вычисление для 2-х воркеров, так чтобы результат от второго воркера пришел раньше, чем от первого: >catch dmap_pmap:map(fun(1, _) -> timer:sleep(2000), 1; (2, _) -> timer:sleep(1000), 2 end, [1, 2], 2, 5000). В последней строчке — результат вычислений. 2) Запустим вычисление для 2-х воркеров, так, чтобы в первом воркере случился креш: >catch dmap_pmap:map(fun(1, _) -> timer:sleep(100), erlang:exit(terrible_error); (2, _) -> timer:sleep(100), 2 end, [1, 2], 2, 5000). 3) Запустим вычисление для 2-х воркеров, так, чтобы время вычисления функции превысило разрешенный таймаут: > catch dmap_pmap:map(fun(1, _) -> timer:sleep(2000), erlang:exit(terrible_error); (2, _) -> timer:sleep(100), 2 end, [1, 2], 2, 1000). Ну и наконец... Результаты тестирования выглядят разумно, но при чем же тут кластер, может спросить внимательный читатель.
На самом деле, оказывается, что у нас уже есть почти все, что нужно, чтобы запустить вычисления на кластере, где под кластером мы понимаем набор связанных Erlang нод. В отдельном модуле dmap_dmap заведем еще одну функцию, со следующей сигнатурой: map({M, F}, Items, WorkersNodes, Timeout) -> {ok, [FnResult]} | {error, timeout}, throws {'EXIT', Reason}, где: Реализация: Логика этой функции очень проста: мы используем функцию dmap_pmap:map из прошлого раздела, в которую подставляем анонимную функцию, которая, в свою очередь, просто выполняет вычисление на нужной ноде.  Для теста в отдельном модуле заведем функцию, которая возвращает имя своей ноды:  Для тестирования нам нужно в двух терминалах запустить по ноде, например, вот так (из рабочего каталога проекта): make run NODE_NAME=n1@127.0.0.1 make run NODE_NAME=n2@127.0.0.1 Запустим вычисление на первой ноде: (n1@127.0.0.1)1> dmap_dmap:map({dmap_test, test}, [1, 2], ['n1@127.0.0.1', 'n2@127.0.0.1'], 5000). И получим результат: Как можно заменить, результаты прилетели от двух нод, как мы и заказывали. Наш простой пример показывает, что в своей сфере применения Erlang позволяет относительно просто решать полезные задачи (которые не так просто решить с помощью других языков программирования).  Из-за короткого формата статьи могут быть вопросы относительно кода и сборки библиотеки, которые остались за кадром. Какие-то детали можно посмотреть в GitHub: тут. Остальные детали мы обещаем осветить в следующих статьях.
 SRE-инженер