Re: Go vs Erlang vs Elixir
От: Лось Чтостряслось СССР  
Дата: 09.02.17 09:22
Оценка: +3 :)
Здравствуйте, chaotic-kotik, Вы писали:

CK>Может кто-нибудь объяснить, почему люди считают что Go подходит для concurrency и сервисов, хотя там нет нормального планировщика (любая горутина может неотдавать управление неограничено долго), общая память и глобальный GC, невозможно нормально остановить горутину, нет нормальной обработки ошибок?


потому что го — это модно, стильно, молодежно
социализм или варварство
Re[5]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 14:03
Оценка: 2 (1) +1
Здравствуйте, Sharov, Вы писали:

N>>* Стандартное "сегодня потребности в колбасе нет" на наследование, исключения и дженерики.

S>Это язык от сишников для сишников, у которых есть потребности в многозадачности. Им вот это вот ООП не требуется.

N>>* Из того, что для моих целей крайне критично — нет приоритетов в select. Наоборот, явно прописан случайный выбор среди доступных — как по мне, это преступление. Случайный выбор должен быть дополнительным режимом, но не по умолчанию, и в идеале — в выделенной подгруппе случаев.

S>Вроде приоритет в порядке следования case'ов?

Прочтите документацию.

If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.


N>>* Народ делает закат солнца вручную написанием своего ассемблера. Его качество резко хуже доступных аналогов вроде gcc и llvm.

S>Не понял об чем речь, какой ассемблер?

Хотя бы вот. Так вот, кодогенерация там очень слабая, если сравнивать с аналогами, где на заточку под процессоры с их возможностями ушло много человеко-лет. Но сделать выхлоп, например, в LLVM IR они не хотят — "у нас всё должно быть на Go".
The God is real, unless declared integer.
Отредактировано 09.02.2017 14:14 netch80 . Предыдущая версия .
Re[3]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 09:37
Оценка: 1 (1) +1
Здравствуйте, chaotic-kotik, Вы писали:

ЛЧ>>потому что го — это модно, стильно, молодежно


CK>Может быть и правда молодежно, я когда на го пишу, сразу вспоминаю юность и турбопаскаль, те же ощущения от языка, что в свое время были от турбопаскаля, руки так и тянутся написать Uses Crt вместо import "fmt"!


Ничего удивительного — Go это паскаль с алголом68 (включая параллельность) в тылу с немного человеческим лицом в стиле C
The God is real, unless declared integer.
Отредактировано 09.02.2017 9:38 netch80 . Предыдущая версия .
Re[7]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 14:16
Оценка: 1 (1) +1
Здравствуйте, Sharov, Вы писали:

S>Ну если для Вас это приоритетно, то делайте select на отдельном канале. Если не ошибаюсь, люди просто скопировали никсовый select-poll. Там вроде тоже нет приоритетов, хотя не уверен.


"Там" пользователь API получает список всех готовых на момент вызова и сам выбирает, как ему строить приоритеты. (И этим пользуются.) В Go аналога этому нет, идёт сразу переход на выбранную рантаймом ветку.
The God is real, unless declared integer.
Re: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 09:43
Оценка: +2
Здравствуйте, chaotic-kotik, Вы писали:

CK>Может кто-нибудь объяснить, почему люди считают что Go подходит для concurrency и сервисов, хотя там нет нормального планировщика (любая горутина может неотдавать управление неограничено долго), общая память и глобальный GC, невозможно нормально остановить горутину, нет нормальной обработки ошибок?

CK>Самое главное, есть же нормальная алтернатива — Erlang/Elixir + OTP.

1. Erlang VM не умеет статическую типизацию. На практике для задач, на которые целится Go, это даёт проигрыш до порядка по скорости.
2. Erlang имеет ряд тяжёлых специфических болезней. Например, неуправляемый входной поток данных — убийство VM. Это проблема VM в целом, Elixir это не вылечит. На практике против последствий этого строят сложные системы управления. Или куча процесса — если процесс толстый, можно не суметь её собрать — это к тому, что глобальный GC может быть даже лучше, чем на отдельный внутренний процесс.

Это не отменяет того, что Go крив как баба-яга после драки, но они тут друг друга стоят.
The God is real, unless declared integer.
Re[2]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 13:39
Оценка: 2 (1)
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, chaotic-kotik, Вы писали:


CK>>Может кто-нибудь объяснить, почему люди считают что Go подходит для concurrency и сервисов, хотя там нет нормального планировщика (любая горутина может неотдавать управление неограничено долго), общая память и глобальный GC, невозможно нормально остановить горутину, нет нормальной обработки ошибок?

CK>>Самое главное, есть же нормальная алтернатива — Erlang/Elixir + OTP.

>>любая горутина может неотдавать управление неограничено долго


S>Откуда инфа?


Например, тут пункт 58.
The God is real, unless declared integer.
Re[11]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 12.02.17 09:51
Оценка: 2 (1)
Здравствуйте, meadow_meal, Вы писали:

_>Вообще по этой задаче у нас есть неконтролируемый входной поток данных и их обработка, и при этом в общем случае отсутствуют какие-либо гарантии, что обработка происходит быстрее, чем поступление данных на вход. То есть проблема уже заложена в постановку задачи.


Если бы реакция на входную очередь была линейной, твои слова были бы совершенно правильны. Пусть есть некоторая пропускная способность системы. Неважно, чему это равно — тысяча или миллион сообщений в секунду — но она есть, её можно измерить. Если где-то возникает затор, накапливается очередь. Торможение не происходит мгновенно, но если нет сильного роста времени обработки одного сообщения в зависимости от уже накопленного — мы с этим справимся в тех же пределах. В реальности надо, конечно, давать какой-то запас — ну, например, 10% обычно достаточно.

Но описанные факторы дают квадратичную зависимость. И из них любое даже небольшое внутреннее переполнение приводит к лавинному эффекту: временная точка затора начинает разбухать.

В последнем из проектов, где я столкнулся с этим, цифры выглядели примерно так: нагрузка растёт ровно до достижения примерно 25K сообщений в секунду. (В разные пробы были заметно разные цифры, от 15K до 30K, и это тоже показательно.) Пока среднее значение длины очереди релейного процесса — до пары десятков сообщений, всё работает. Но чем выше, тем больше вероятность того, что очередь скакнёт до сотен просто из-за того, что шедулинг не успевает переключать процессы; это чисто стохастический процесс. По достижению этого уровня (сотни сообщений в очереди) релеинг фактически останавливается, снижая скорость, причём до чудовищно низких величин (когда 3K, а когда и просто сотни сообщений в секунду). Далее срабатывал регулятор нагрузки в тесте и снижал её, но привести систему к исходному состоянию можно было только добившись снижения темпа (или полной остановки) до того, что очередь на релейном процессе падала почти до нуля. Тогда его скорость восстанавливалась.

Мы пробовали ставить реакцию на переполнение на приёмной точке (куда входит TCP соединение). Да, это работало. Надо было нарисовать более-менее умную полиси типа "если обнаружили в какой-то момент затор (затор определили как более 1000 сообщений в очереди у приёмного процесса), прекратить приём и ждать, пока не упадёт до 0 (на самом деле поставили — до менее 10 сообщений). Да, в таком варианте работало. Но, за счёт частых впаданий в переполнение, суммарная скорость оказывалась ниже возможной устойчивой. Чтобы получить более-менее устойчивую устойчивость потока, извините за каламбур, пришлось принудительно снижать скорость потока до менее чем половины от предельно известной до начала турбулентности. (Валкин делал что-то похожее.)

_> Selective receive это возможный катализатор (а если используется gen:call, то и не факт), а никак не причина. Рано или поздно очередь будет расти, а это всегда проблема (даже если не дойдет до OOM, то те же control messages будут приходить слишком поздно и т.п.).


Это именно что причина. Другие решения, где я устраняю последовательный перебор очереди за счёт разных очередей, не имеют такой проблемы, потому что обработка одного сообщения не выходит за O(1).
(Разумеется, я не имею в виду ситуацию типа "очередь выжрала всю RAM". Но когда у тебя начинается торможение на 1/100-1/1000 от доступной RAM — это, мягко говоря, неадекватно.)

_>Буферный процесс для входящего потока мог бы решить проблему. Он бы просто складывал сообщения в буфер, а мы бы загребали их у него пачками (посылая асинхронное уведомление о готовности обработать не более N сообщений). В итоге наш отправляющий процесс имеет контролируемый входной поток сообщений.


Плохо. Потому что ещё есть проблема задержки. Задержку тоже надо уменьшать.
Если мы будем действовать по принципу "всю предыдущую порцию отработали и тогда просим следующую" — она будет большой и неравномерной. Чтобы она была равномерной — надо делать по принципу "пока одно сообщение отработали и подтвердили, ещё NN ползёт по буферам и очередям". А в этом случае, как показала практика, регулировка просто не успевает срабатывать до того, как очередь вырастет раза в 3-4, а время обработки соответственно на порядок.

_> Что до буферного, то придется решить, что делать при переполнении — но здесь мы хотя бы это сами контролируем. Переполнение может произойти в любом случае, нельзя просто надеяться что мы отправляем быстрее чем получаем, и selective receive здесь не виноват.


Виноват. См. выше.

_>Вообще, здесь на rsdn уже несколько раз читал (в сообщениях разных людей), что медленный selective receive — это родовая травма эрланга и чуть ли не повод его не использовать. Мне это кажется сомнительным, там, где selective receive приводит к проблемам, проблемы возникли бы (чуть позже, но со всей вероятностью) и имей selective receive константную сложность. Просто неконтролируемый входной поток надо делать контролируемым.


В теории, может, и получается. На практике регуляторы не успевают до начала существенных заторов. Как уже сказал, после начала затора единственное, что сработает — "задушить" вход до полной расчистки затора. Результат — низкая средняя скорость и чудовищный jitter.

_>Сейчас пробежался глазами, кажется, то же самое предложил Masterspline в этом сообщении:


M>>Вариант номер два: делаешь отправку в отдельной корутине, туда же придет и ответ по tcp, и там не будет такой очереди.

N>>Проходили. Не работает. Сам догадаешься, почему?
_>Вот значит я не догадался. Почему? (На случай если я неверно понял, что именно предложил Masterspline, и это совсем другое, то меня конечно больше интересуют недостатки моего собственного предложения)

Потому что отдельная "корутина" (внутренний процесс Erlang) точно так же имеет ровно одну входную очередь с теми же проблемами, и эти проблемы перенесутся на неё один к одному.
Сколько бы ты промежуточных процессов ни ставил — у какого-то из них будут те же проблемы, и пока не сделаешь какой-то другой канал передачи информации — его будет плющить. А немедленной побудки по другому каналу не сделаешь.
The God is real, unless declared integer.
Re[2]: Go vs Erlang vs Elixir
От: chaotic-kotik  
Дата: 09.02.17 11:31
Оценка: 1 (1)
Здравствуйте, Sharov, Вы писали:

>>любая горутина может неотдавать управление неограничено долго


S>Откуда инфа?


Компилятор го вставляет вызовы runtime.Gosched перед некоторыми конструкциями, чтобы шедулер получал управление и мог прервать выполнение кода. В BEAM вытесняющая многозадачность, а в Go — кооперативная, со всеми вытекающими проблемами.


>>общая память


S>Вроде по уму, через каналы. Или это опять не то?


И через мьютексы и общую память.
Re[3]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 13:45
Оценка: 1 (1)
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, netch80, Вы писали:


N>>Это не отменяет того, что Go крив как баба-яга после драки, но они тут друг друга стоят.


S>Чем он крив?


неплохой сборник особенностей. Как по мне, большинство в минус.
1 — Нет возможности указать, что строка продолжается (как финальная \ в Python), собственные правила для этого достаточно путаны.
2,3 — Хорошо до тех пор, пока не хочешь чего-то временно закомментировать, или если код генерится автоматом. Считаю, что не дело языка навязывать тут политику.
5 — тупой ляп дизайна.
7 — надо было хотя бы предупреждения делать.
10 — недоработка.
19 — не зря в Питоне отдельные байтовые строки.
Из того, что не упомянуто
* Экспорт по регистру — абсолютно тупая идея с неприятными последствиями в виде массовых замен при реэкспорте.
* На тупизну их модуля http не жалуется только ленивый. Остальная библиотека не сильно лучше, слишком много сделанного совсем на коленке.
* Стандартное "сегодня потребности в колбасе нет" на наследование, исключения и дженерики.
* Из того, что для моих целей крайне критично — нет приоритетов в select. Наоборот, явно прописан случайный выбор среди доступных — как по мне, это преступление. Случайный выбор должен быть дополнительным режимом, но не по умолчанию, и в идеале — в выделенной подгруппе случаев.
* Народ делает закат солнца вручную написанием своего ассемблера. Его качество резко хуже доступных аналогов вроде gcc и llvm.
The God is real, unless declared integer.
Re[5]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 15:27
Оценка: 1 (1)
Здравствуйте, chaotic-kotik, Вы писали:

N>>Процесс не может регулировать, что ему отправляется в mailbox. Mailbox один для сообщений всех типов и источников. При его большой длине синхронные взаимодействия начинают стоить пропорционально длине очереди каждое, а в сумме получается квадратичная зависимость. Некоторые действия даже по избавлению от данных (как gen_tcp:send) требуют обратного приёма сообщения, соответственно, там получается то же O(n^2).

CK>Я вот как-то не очень понимаю (совсем не) как получается O(n2? Если процесс А отправил сообщение процессу В, а у того mailbox забит и он его разгребвает, то количество сообщений, которые он разгребет до того как отправить ответ процессу А, действительно зависит от количества сообщений в mailbox-е. Но он ведь в любом случае должен все эти сообщения обработать, не?

Удобный пример — конвертилка чего-то внутреннего формата в сообщения протокола поверх TCP и отправлялка в мир.
На вход поступило N сообщений. Выбрали первое, сериализовали, вызвали отправку через gen_tcp:send(). Та через несколько уровней дошла до вызова порта и ожидания сообщения в ответ(!) о том, что порт отработал команду записи.
В это время процесс сидит в receive. Чтобы перебрать всю очередь и перейти в ожидание, ему нужно прошерстить N-1 сообщение (одно мы только что забрали). Дальше он ждёт (или не ждёт, если ответ порта уже успел прийти).
OK, осталось N-1. Та же процедура, пересканировать вход, пропустив N-2 сообщения.
И так далее.
То есть, если новых не поступит, время отработки пропорционально квадрату количества поступивших (точнее, каждый может подсчитать, чему равно (N-1)+(N-2)+(N-3)+..., но мне облом — асимпотически это равно N*N/2). [UPD: исправил формулу]

И подобные ситуации не только с TCP, а с любым случаем, где владелец длинной очереди синхронно с кем-то общается (то есть, дожидаясь ответа).
(Да, оптимизации R14 про watermark на эту очередь не вспоминать — они тут не помогают.)

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

CK>Я думал что там проблема в том, что процессу могут накидать столько, что он грохнется по OOM. Но это by design. Если делать блокирующие ограниченые очереди как в Go, то непонятно как это должно быть реализовано, если процесс на другой машине.


Можно просто не принять и продискардить. Если разрешено опциями посылки.
Можно придумать блокирующий межнодовый send для этого (а лучше — с таймаутом).
В конце концов, опыт UDP, TCP, SCTP уже многолетний. Перенести его не проблема.
The God is real, unless declared integer.
Отредактировано 09.02.2017 19:47 netch80 . Предыдущая версия .
Re[9]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 10.02.17 06:12
Оценка: 1 (1)
Здравствуйте, Sharov, Вы писали:

S> С другой стороны в выше процитированной док-ии сказано, что выч. на канале идут в порядке следования их case'ов.


Вычисления. Но не пробы каналов. Подозреваю, что тут есть существенная разница.

S> И как бэ неявно приоритет будет отдаваться первому, наверное.


Есть исходники, я читаю по ним (по 1.7.5).
Файл go/work/src/runtime/select.go, функция selectGoImpl(). В массиве pollorder генерируется перестановка, на каждый запуск select{} своя. По ней сортируется массив lockorder (код сортировки, как это у них принято, повторен и вшит прямо на месте в функцию). Дальше в порядке этого lockorder они двигаются по кейсам.
Никакого предпочтения первому — нет.

S> В целом было логично, что если первый case готов -- управление ему, иначе рандомный выбор.


Не логично. Логично или строго по порядку, или по явно прописанным приоритетам (я бы предпочёл схему, как в DNS SRV записях — есть priority и есть weight).

И ещё обязательно должна быть возможность таймаута. Её сейчас тоже нет.
The God is real, unless declared integer.
Re[10]: Go vs Erlang vs Elixir
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.02.17 13:38
Оценка: 1 (1)
Здравствуйте, netch80, Вы писали:

N>Не логично. Логично или строго по порядку, или по явно прописанным приоритетам (я бы предпочёл схему, как в DNS SRV записях — есть priority и есть weight).


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

N>И ещё обязательно должна быть возможность таймаута. Её сейчас тоже нет.


Просто добавляем в select case, в который таймер тикает. Это ничем не хуже какого-то отдельного механизма для таймаута.
Re[2]: Go vs Erlang vs Elixir
От: chaotic-kotik  
Дата: 09.02.17 09:31
Оценка: +1
Здравствуйте, Лось Чтостряслось, Вы писали:

ЛЧ>потому что го — это модно, стильно, молодежно


Может быть и правда молодежно, я когда на го пишу, сразу вспоминаю юность и турбопаскаль, те же ощущения от языка, что в свое время были от турбопаскаля, руки так и тянутся написать Uses Crt вместо import "fmt"!
Re: Go vs Erlang vs Elixir
От: TK Лес кывт.рф
Дата: 09.02.17 12:18
Оценка: +1
Здравствуйте, chaotic-kotik, Вы писали:

CK>любая горутина может неотдавать управление неограничено долго


В Go приложения на текущий момент монолитные — т.е. если горутина не отдает управление то это только потому, что это выбор разработчика.
А писать так, что одна рука не знает что делает другая — оно конечно можно но, зачем?
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Go vs Erlang vs Elixir
От: chaotic-kotik  
Дата: 09.02.17 09:12
Оценка:
Может кто-нибудь объяснить, почему люди считают что Go подходит для concurrency и сервисов, хотя там нет нормального планировщика (любая горутина может неотдавать управление неограничено долго), общая память и глобальный GC, невозможно нормально остановить горутину, нет нормальной обработки ошибок?
Самое главное, есть же нормальная алтернатива — Erlang/Elixir + OTP.
Re: Go vs Erlang vs Elixir
От: Sharov Россия  
Дата: 09.02.17 11:01
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

CK>Может кто-нибудь объяснить, почему люди считают что Go подходит для concurrency и сервисов, хотя там нет нормального планировщика (любая горутина может неотдавать управление неограничено долго), общая память и глобальный GC, невозможно нормально остановить горутину, нет нормальной обработки ошибок?

CK>Самое главное, есть же нормальная алтернатива — Erlang/Elixir + OTP.

>любая горутина может неотдавать управление неограничено долго


Откуда инфа?


>общая память


Вроде по уму, через каналы. Или это опять не то?
Кодом людям нужно помогать!
Re[2]: Go vs Erlang vs Elixir
От: Sharov Россия  
Дата: 09.02.17 11:04
Оценка:
Здравствуйте, netch80, Вы писали:

N>Это не отменяет того, что Go крив как баба-яга после драки, но они тут друг друга стоят.


Чем он крив? Я интересуюсь не ради спора, т.к. начал изучать язык буквально неделю назад. Пока все нравится -- каналы, горутины, select'ы (poll). Вроде неплохо для легко масштабируемых веб-сервисов. С указателями можно на прямую работать, т.е. сишники могут запрыгнуть.
Кодом людям нужно помогать!
Re[2]: Go vs Erlang vs Elixir
От: neFormal Россия  
Дата: 09.02.17 11:16
Оценка:
Здравствуйте, netch80, Вы писали:

N>2. Erlang имеет ряд тяжёлых специфических болезней. Например, неуправляемый входной поток данных — убийство VM.

N>На практике против последствий этого строят сложные системы управления.

это как "неуправляемый"?
и о каких системах речь?

N>Или куча процесса — если процесс толстый, можно не суметь её собрать — это к тому, что глобальный GC может быть даже лучше, чем на отдельный внутренний процесс.


а тут что помешает?
gc же на каждый шедулер, а не на процесс.
...coding for chaos...
Re[2]: Go vs Erlang vs Elixir
От: chaotic-kotik  
Дата: 09.02.17 11:21
Оценка:
Здравствуйте, netch80, Вы писали:

N>1. Erlang VM не умеет статическую типизацию. На практике для задач, на которые целится Go, это даёт проигрыш до порядка по скорости.


Для критичных к производительности участков есть NIF-ы и порты.
Ну а для статических проверок есть dialyzer.

N>2. Erlang имеет ряд тяжёлых специфических болезней. Например, неуправляемый входной поток данных — убийство VM. Это проблема VM в целом, Elixir это не вылечит. На практике против последствий этого строят сложные системы управления. Или куча процесса — если процесс толстый, можно не суметь её собрать — это к тому, что глобальный GC может быть даже лучше, чем на отдельный внутренний процесс.


А можно подробней, я не понял о чем идет речь.
Отредактировано 09.02.2017 11:26 chaotic-kotik . Предыдущая версия .
Re: Go vs Erlang vs Elixir
От: Слава  
Дата: 09.02.17 11:38
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

CK>Самое главное, есть же нормальная алтернатива — Erlang/Elixir + OTP.


Потому что Go — простая и понятная императивщина. А если ты хочешь почувствовать неудобство функциональщины, как его чувствуют другие люди — возьми LanguageExt. Вот уж дрянь из дряней.
Re[2]: Go vs Erlang vs Elixir
От: chaotic-kotik  
Дата: 09.02.17 12:00
Оценка:
Здравствуйте, Слава, Вы писали:

С>Потому что Go — простая и понятная императивщина. А если ты хочешь почувствовать неудобство функциональщины, как его чувствуют другие люди — возьми LanguageExt. Вот уж дрянь из дряней.


Ну это уже какие-то ваши детские травмы. Elixir это Lisp, только с нормальным синтаксисом + BEAM + OTP. Ну а .NET это всегда боль и унижение.
Re[3]: Go vs Erlang vs Elixir
От: neFormal Россия  
Дата: 09.02.17 12:31
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

CK>Ну это уже какие-то ваши детские травмы. Elixir это Lisp, только с нормальным синтаксисом + BEAM + OTP. Ну а .NET это всегда боль и унижение.


при чём тут лисп?
...coding for chaos...
Re[3]: Go vs Erlang vs Elixir
От: DrDred Россия  
Дата: 09.02.17 12:40
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

CK>Ну это уже какие-то ваши детские травмы. Elixir это Lisp, только с нормальным синтаксисом + BEAM + OTP. Ну а .NET это всегда боль и унижение.


Почему Lisp? Вроде автор писал, что вдохновлялся Ruby в основном...
--
WBR, Alexander
Re[4]: Go vs Erlang vs Elixir
От: chaotic-kotik  
Дата: 09.02.17 12:52
Оценка:
Здравствуйте, DrDred, Вы писали:

DD>Почему Lisp? Вроде автор писал, что вдохновлялся Ruby в основном...


А получился полноценный Lisp!
Re: Go vs Erlang vs Elixir
От: VTT http://vtt.to
Дата: 09.02.17 13:07
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

CK>Может кто-нибудь объяснить, почему люди считают что Go подходит для concurrency и сервисов, хотя там нет нормального планировщика (любая горутина может неотдавать управление неограничено долго), общая память и глобальный GC, невозможно нормально остановить горутину, нет нормальной обработки ошибок?


Так гугл же форсит его, как только можно.

CK>Самое главное, есть же нормальная алтернатива — Erlang/Elixir + OTP.


go мне представляется скорее альтернативой джаве, только с еще более низкими требованиями к кодерам.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[2]: Go vs Erlang vs Elixir
От: Sharov Россия  
Дата: 09.02.17 13:16
Оценка:
Здравствуйте, VTT, Вы писали:


CK>>Может кто-нибудь объяснить, почему люди считают что Go подходит для concurrency и сервисов, хотя там нет нормального планировщика (любая горутина может неотдавать управление неограничено долго), общая память и глобальный GC, невозможно нормально остановить горутину, нет нормальной обработки ошибок?


VTT>Так гугл же форсит его, как только можно.


Например? Языку шесть лет как минимум, особо про него ничего не слышно. Сообщество у него не очень больше. В самом то гугле на нем что написано?

CK>>Самое главное, есть же нормальная алтернатива — Erlang/Elixir + OTP.


VTT>go мне представляется скорее альтернативой джаве, только с еще более низкими требованиями к кодерам.


Куда уж ниже требования? Go явно не альтернатива жабе, скорее язык где мн-во многопоточных идиом изкаропки. Он больше конкурент erlang'у.
Кодом людям нужно помогать!
Re[3]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 13:50
Оценка:
Здравствуйте, neFormal, Вы писали:

N>>2. Erlang имеет ряд тяжёлых специфических болезней. Например, неуправляемый входной поток данных — убийство VM.

N>>На практике против последствий этого строят сложные системы управления.
F>это как "неуправляемый"?

Процесс не может регулировать, что ему отправляется в mailbox. Mailbox один для сообщений всех типов и источников. При его большой длине синхронные взаимодействия начинают стоить пропорционально длине очереди каждое, а в сумме получается квадратичная зависимость. Некоторые действия даже по избавлению от данных (как gen_tcp:send) требуют обратного приёма сообщения, соответственно, там получается то же O(n^2).

F>и о каких системах речь?


Лев Валкин (lionet@), например, строил демпферы на точках передачи между нодами, оповещая их о состоянии приёмных процессов. У него целый фреймворк был для этого.

N>>Или куча процесса — если процесс толстый, можно не суметь её собрать — это к тому, что глобальный GC может быть даже лучше, чем на отдельный внутренний процесс.


F>а тут что помешает?

F>gc же на каждый шедулер, а не на процесс.

В Erlang — по умолчанию на процесс, кроме общей кучи на толстые бинари. При запуске GC процесса должно быть достаточно свободной памяти, чтобы сделать копию всех выживших данных. Отсюда конструкции с небольшим количеством очень толстых процессов имеют шанс убить целиком еноду.
The God is real, unless declared integer.
Re[3]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 13:53
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

N>>1. Erlang VM не умеет статическую типизацию. На практике для задач, на которые целится Go, это даёт проигрыш до порядка по скорости.

CK>Для критичных к производительности участков есть NIF-ы и порты.

Есть. Что означает, что отказываемся от всех преимуществ managed устройства и приходим к голому C.

N>>2. Erlang имеет ряд тяжёлых специфических болезней. Например, неуправляемый входной поток данных — убийство VM. Это проблема VM в целом, Elixir это не вылечит. На практике против последствий этого строят сложные системы управления. Или куча процесса — если процесс толстый, можно не суметь её собрать — это к тому, что глобальный GC может быть даже лучше, чем на отдельный внутренний процесс.


CK>А можно подробней, я не понял о чем идет речь.


Я вообще-то об этом писал кучу раз, но если хочется повторения — см. предыдущий мой постинг в эту тему.
The God is real, unless declared integer.
Re[3]: Go vs Erlang vs Elixir
От: VTT http://vtt.to
Дата: 09.02.17 13:57
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Здравствуйте, VTT, Вы писали:



CK>>>Может кто-нибудь объяснить, почему люди считают что Go подходит для concurrency и сервисов, хотя там нет нормального планировщика (любая горутина может неотдавать управление неограничено долго), общая память и глобальный GC, невозможно нормально остановить горутину, нет нормальной обработки ошибок?


VTT>>Так гугл же форсит его, как только можно.


S>Например? Языку шесть лет как минимум, особо про него ничего не слышно. Сообщество у него не очень больше. В самом то гугле на нем что написано?


т.е. как это не слышно? Вот в соседнем треде обсуждают, как го стал языком 2016 года. Компилятор go вошел в gcc. Вакансии есть.
А вот об эраланге как раз действительно мало что слышно.

CK>>>Самое главное, есть же нормальная алтернатива — Erlang/Elixir + OTP.


VTT>>go мне представляется скорее альтернативой джаве, только с еще более низкими требованиями к кодерам.


S>Куда уж ниже требования? Go явно не альтернатива жабе, скорее язык где мн-во многопоточных идиом изкаропки. Он больше конкурент erlang'у.


Какое множество? Запустил горутину, прокачал канал и готово.
т.е. средства там есть, но среднестатистическому го-разработчику они вряд ли понадобится.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re[4]: Go vs Erlang vs Elixir
От: Sharov Россия  
Дата: 09.02.17 13:58
Оценка:
Здравствуйте, netch80, Вы писали:

N>* Стандартное "сегодня потребности в колбасе нет" на наследование, исключения и дженерики.


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

N>* Из того, что для моих целей крайне критично — нет приоритетов в select. Наоборот, явно прописан случайный выбор среди доступных — как по мне, это преступление. Случайный выбор должен быть дополнительным режимом, но не по умолчанию, и в идеале — в выделенной подгруппе случаев.


Вроде приоритет в порядке следования case'ов?

N>* Народ делает закат солнца вручную написанием своего ассемблера. Его качество резко хуже доступных аналогов вроде gcc и llvm.


Не понял об чем речь, какой ассемблер?
Кодом людям нужно помогать!
Re[6]: Go vs Erlang vs Elixir
От: Sharov Россия  
Дата: 09.02.17 14:13
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, Sharov, Вы писали:


N>>>* Стандартное "сегодня потребности в колбасе нет" на наследование, исключения и дженерики.

S>>Это язык от сишников для сишников, у которых есть потребности в многозадачности. Им вот это вот ООП не требуется.

N>>>* Из того, что для моих целей крайне критично — нет приоритетов в select. Наоборот, явно прописан случайный выбор среди доступных — как по мне, это преступление. Случайный выбор должен быть дополнительным режимом, но не по умолчанию, и в идеале — в выделенной подгруппе случаев.

S>>Вроде приоритет в порядке следования case'ов?

N>Ну прочтите же вы документацию.

N>

If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.


Да, вот с этим перепутал:

For all the cases in the statement, the channel operands of receive operations and the channel and right-hand-side expressions of send statements are evaluated exactly once, in source order, upon entering the "select" statement.



Ну если для Вас это приоритетно, то делайте select на отдельном канале. Если не ошибаюсь, люди просто скопировали никсовый select-poll. Там вроде тоже нет приоритетов, хотя не уверен.
Кодом людям нужно помогать!
Re[4]: Go vs Erlang vs Elixir
От: neFormal Россия  
Дата: 09.02.17 14:14
Оценка:
Здравствуйте, netch80, Вы писали:

N>Процесс не может регулировать, что ему отправляется в mailbox. Mailbox один для сообщений всех типов и источников. При его большой длине синхронные взаимодействия начинают стоить пропорционально длине очереди каждое, а в сумме получается квадратичная зависимость. Некоторые действия даже по избавлению от данных (как gen_tcp:send) требуют обратного приёма сообщения, соответственно, там получается то же O(n^2).


ну да, но чтобы это было убийством — ну фиг знает.

N>Лев Валкин (lionet@), например, строил демпферы на точках передачи между нодами, оповещая их о состоянии приёмных процессов. У него целый фреймворк был для этого.


ага, дистрибушон — слабое место.

N>В Erlang — по умолчанию на процесс, кроме общей кучи на толстые бинари. При запуске GC процесса должно быть достаточно свободной памяти, чтобы сделать копию всех выживших данных. Отсюда конструкции с небольшим количеством очень толстых процессов имеют шанс убить целиком еноду.


откуда там отдельные gc?
то, что процессы отдают память лишь в двух случаях передачи управления другим процессам, не значит, что у каждого по отдельному gc.
просто при передаче управления они выкидывают уже ненужное. и "общая куча" при этом тоже имеет возможность избавиться от лишнего.
...coding for chaos...
Re[5]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 14:28
Оценка:
Здравствуйте, neFormal, Вы писали:

N>>Процесс не может регулировать, что ему отправляется в mailbox. Mailbox один для сообщений всех типов и источников. При его большой длине синхронные взаимодействия начинают стоить пропорционально длине очереди каждое, а в сумме получается квадратичная зависимость. Некоторые действия даже по избавлению от данных (как gen_tcp:send) требуют обратного приёма сообщения, соответственно, там получается то же O(n^2).

F>ну да, но чтобы это было убийством — ну фиг знает.

Ну мне сложно подобрать иной термин, как "убийство проекта", для того, что мне пришлось выкинуть Erlang-версию и срочно перегнать приблуду (специализированный прокси) на C++.
Появился гимор с управлением памятью, зато исчез — с неуправляемыми заклинами всего приложения под нагрузкой.

N>>Лев Валкин (lionet@), например, строил демпферы на точках передачи между нодами, оповещая их о состоянии приёмных процессов. У него целый фреймворк был для этого.

F>ага, дистрибушон — слабое место.

Там был не то чтобы distribution...

N>>В Erlang — по умолчанию на процесс, кроме общей кучи на толстые бинари. При запуске GC процесса должно быть достаточно свободной памяти, чтобы сделать копию всех выживших данных. Отсюда конструкции с небольшим количеством очень толстых процессов имеют шанс убить целиком еноду.


F>откуда там отдельные gc?

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

Не значит, но факт тот, что там отдельные кучи у каждого процесса.

F>просто при передаче управления они выкидывают уже ненужное. и "общая куча" при этом тоже имеет возможность избавиться от лишнего.


Нет. GC срабатывает в каждом процессе отдельно и по превышению им количества так называемых reductions с прошлого старта GC. Reduction — это, грубо говоря, любая элементарная операция интерпретатора (один оператор выражения, один вызов функции, один простой матчинг-биндинг и т.п.) В последних релизах разделены поколения и полная сборка, но по-прежнему по процессам раздельно. Читайте начиная с process_flag(fullsweep_after).
The God is real, unless declared integer.
Re[6]: Go vs Erlang vs Elixir
От: neFormal Россия  
Дата: 09.02.17 14:52
Оценка:
Здравствуйте, netch80, Вы писали:

N>Ну мне сложно подобрать иной термин, как "убийство проекта", для того, что мне пришлось выкинуть Erlang-версию и срочно перегнать приблуду (специализированный прокси) на C++.

N>Появился гимор с управлением памятью, зато исчез — с неуправляемыми заклинами всего приложения под нагрузкой.

это до следующего уровня нагрузки.
дропать сообщеньки надо. ну, если нет больших проблем с постановкой сообщенек самому себе, тогда совсем всё плохо.

N>>>Лев Валкин (lionet@), например, строил демпферы на точках передачи между нодами, оповещая их о состоянии приёмных процессов. У него целый фреймворк был для этого.

F>>ага, дистрибушон — слабое место.
N>Там был не то чтобы distribution...

а зачем тогда? выравнивал нагрузку между нодами?

N>Не значит, но факт тот, что там отдельные кучи у каждого процесса.


да как бы и нет. если нужна память, процесс её берёт у VM, которая берёт её у системы.
память берётся чанками и освобождается в паре ситуаций.

F>>просто при передаче управления они выкидывают уже ненужное. и "общая куча" при этом тоже имеет возможность избавиться от лишнего.

N>Нет. GC срабатывает в каждом процессе отдельно и по превышению им количества так называемых reductions с прошлого старта GC. Reduction — это, грубо говоря, любая элементарная операция интерпретатора (один оператор выражения, один вызов функции, один простой матчинг-биндинг и т.п.) В последних релизах разделены поколения и полная сборка, но по-прежнему по процессам раздельно. Читайте начиная с process_flag(fullsweep_after).

да что-то ни разу не так.
память чистится либо при завершении процесса, либо с hibernate из gen_server'а.
...coding for chaos...
Re[4]: Go vs Erlang vs Elixir
От: chaotic-kotik  
Дата: 09.02.17 15:07
Оценка:
Здравствуйте, netch80, Вы писали:

N>Процесс не может регулировать, что ему отправляется в mailbox. Mailbox один для сообщений всех типов и источников. При его большой длине синхронные взаимодействия начинают стоить пропорционально длине очереди каждое, а в сумме получается квадратичная зависимость. Некоторые действия даже по избавлению от данных (как gen_tcp:send) требуют обратного приёма сообщения, соответственно, там получается то же O(n^2).


Я вот как-то не очень понимаю (совсем не) как получается O(n2? Если процесс А отправил сообщение процессу В, а у того mailbox забит и он его разгребвает, то количество сообщений, которые он разгребет до того как отправить ответ процессу А, действительно зависит от количества сообщений в mailbox-е. Но он ведь в любом случае должен все эти сообщения обработать, не?

Я думал что там проблема в том, что процессу могут накидать столько, что он грохнется по OOM. Но это by design. Если делать блокирующие ограниченые очереди как в Go, то непонятно как это должно быть реализовано, если процесс на другой машине.
Re[8]: Go vs Erlang vs Elixir
От: Sharov Россия  
Дата: 09.02.17 15:16
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, Sharov, Вы писали:


S>>Ну если для Вас это приоритетно, то делайте select на отдельном канале. Если не ошибаюсь, люди просто скопировали никсовый select-poll. Там вроде тоже нет приоритетов, хотя не уверен.


N>"Там" пользователь API получает список всех готовых на момент вызова и сам выбирает, как ему строить приоритеты. (И этим пользуются.) В Go аналога этому нет, идёт сразу переход на выбранную рантаймом ветку.


Тут согласен. Я думаю они все прекрасно понимали, и рассчитывали что вне циклов использовать select смысла нет, поэтому приоритетное событие никуда не убежит. Имело ли смысли усложнять язык ради метки приоритета -- . Они посчитали, что нет. С другой стороны в выше процитированной док-ии сказано, что выч. на канале идут в порядке следования их case'ов. И как бэ неявно приоритет будет отдаваться первому, наверное. В целом было логично, что если первый case готов -- управление ему, иначе рандомный выбор.
Кодом людям нужно помогать!
Re[6]: Go vs Erlang vs Elixir
От: Слава  
Дата: 09.02.17 15:18
Оценка:
Здравствуйте, netch80, Вы писали:

N>>>Процесс не может регулировать, что ему отправляется в mailbox. Mailbox один для сообщений всех типов и источников. При его большой длине синхронные взаимодействия начинают стоить пропорционально длине очереди каждое, а в сумме получается квадратичная зависимость. Некоторые действия даже по избавлению от данных (как gen_tcp:send) требуют обратного приёма сообщения, соответственно, там получается то же O(n^2).

F>>ну да, но чтобы это было убийством — ну фиг знает.

N>Ну мне сложно подобрать иной термин, как "убийство проекта", для того, что мне пришлось выкинуть Erlang-версию и срочно перегнать приблуду (специализированный прокси) на C++.

N>Появился гимор с управлением памятью, зато исчез — с неуправляемыми заклинами всего приложения под нагрузкой.

На Эрланге я не писал ничего за пределами тестового задания для конторы уже упомянутого @lionet, но мне интересно — если это у вас был прокси, то неужто нельзя было просто раскидывать запросы по нескольким узлам?
Re[6]: Go vs Erlang vs Elixir
От: chaotic-kotik  
Дата: 09.02.17 15:46
Оценка:
Здравствуйте, netch80, Вы писали:

N>Удобный пример — конвертилка чего-то внутреннего формата в сообщения протокола поверх TCP и отправлялка в мир.

N>На вход поступило N сообщений. Выбрали первое, сериализовали, вызвали отправку через gen_tcp:send(). Та через несколько уровней дошла до вызова порта и ожидания сообщения в ответ(!) о том, что порт отработал команду записи.
N>В это время процесс сидит в receive. Чтобы перебрать всю очередь и перейти в ожидание, ему нужно прошерстить N-1 сообщение (одно мы только что забрали). Дальше он ждёт (или не ждёт, если ответ порта уже успел прийти).
N>OK, осталось N-1. Та же процедура, пересканировать вход, пропустив N-2 сообщения.
N>И так далее.
N>То есть, если новых не поступит, время отработки пропорционально квадрату количества поступивших (точнее, каждый может подсчитать, чему равно N*(N-1)+(N-1)*(N-2)+(N-2)*(N-3)+..., но мне облом — асимпотически это равно N*N/2).

Т.е. это все в том случае, если используется selective receive. Тогда понятно, спасибо за разъяснения.
Re[7]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 17:10
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

CK>Т.е. это все в том случае, если используется selective receive. Тогда понятно, спасибо за разъяснения.


Ну да. Проблема в том, что оно используется дофига где и в самых ключевых механизмах, так что даже искоренив его в своём коде, можно получить такое же неожиданно в библиотечной функции.
The God is real, unless declared integer.
Re[7]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 18:01
Оценка:
Здравствуйте, neFormal, Вы писали:

N>>Ну мне сложно подобрать иной термин, как "убийство проекта", для того, что мне пришлось выкинуть Erlang-версию и срочно перегнать приблуду (специализированный прокси) на C++.

N>>Появился гимор с управлением памятью, зато исчез — с неуправляемыми заклинами всего приложения под нагрузкой.
F>это до следующего уровня нагрузки.
F>дропать сообщеньки надо. ну, если нет больших проблем с постановкой сообщенек самому себе, тогда совсем всё плохо.

Специфика — я не имею право ничего дропать. Могу разве что убить соединение целиком. Но после реконнекта пойдёт всё заново литься, с наверняка тем же результатом.

N>>>>Лев Валкин (lionet@), например, строил демпферы на точках передачи между нодами, оповещая их о состоянии приёмных процессов. У него целый фреймворк был для этого.

F>>>ага, дистрибушон — слабое место.
N>>Там был не то чтобы distribution...
F>а зачем тогда? выравнивал нагрузку между нодами?

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

N>>Не значит, но факт тот, что там отдельные кучи у каждого процесса.

F>да как бы и нет. если нужна память, процесс её берёт у VM, которая берёт её у системы.
F>память берётся чанками и освобождается в паре ситуаций.

Да. Включая full GC.

F>>>просто при передаче управления они выкидывают уже ненужное. и "общая куча" при этом тоже имеет возможность избавиться от лишнего.

N>>Нет. GC срабатывает в каждом процессе отдельно и по превышению им количества так называемых reductions с прошлого старта GC. Reduction — это, грубо говоря, любая элементарная операция интерпретатора (один оператор выражения, один вызов функции, один простой матчинг-биндинг и т.п.) В последних релизах разделены поколения и полная сборка, но по-прежнему по процессам раздельно. Читайте начиная с process_flag(fullsweep_after).

F>да что-то ни разу не так.

F>память чистится либо при завершении процесса, либо с hibernate из gen_server'а.

Или на ходу работы. Я не знаю, как ты этого не видишь, можно элементарным образом показать.

Может, у тебя были просто короткоживущие процессы. У меня в нескольких крайне важных случаях был пул долгоживущих.
The God is real, unless declared integer.
Re[7]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 18:05
Оценка:
Здравствуйте, Слава, Вы писали:

N>>Ну мне сложно подобрать иной термин, как "убийство проекта", для того, что мне пришлось выкинуть Erlang-версию и срочно перегнать приблуду (специализированный прокси) на C++.

N>>Появился гимор с управлением памятью, зато исчез — с неуправляемыми заклинами всего приложения под нагрузкой.

С>На Эрланге я не писал ничего за пределами тестового задания для конторы уже упомянутого @lionet, но мне интересно — если это у вас был прокси, то неужто нельзя было просто раскидывать запросы по нескольким узлам?


Специфика задачи — нельзя ничего раскидывать. Да и не сильно оно бы помогло.
The God is real, unless declared integer.
Re[6]: Go vs Erlang vs Elixir
От: meadow_meal  
Дата: 09.02.17 19:06
Оценка:
Здравствуйте, netch80, Вы писали:

N>На вход поступило N сообщений. Выбрали первое, сериализовали, вызвали отправку через gen_tcp:send(). Та через несколько уровней дошла до вызова порта и ожидания сообщения в ответ(!) о том, что порт отработал команду записи.

...
N>В одну очередь это не лечится. Нужно делать много. И по умолчанию разделять очередь обычной посылки и очередь ответов на синхронные запросы.

А так не лечится?
http://www.rigtorp.se/latency.html
Или так:
https://github.com/jashmenn/rabbitmq-server/blob/master/src/rabbit_writer.erl

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

N>И подобные ситуации не только с TCP, а с любым случаем, где владелец длинной очереди синхронно с кем-то общается (то есть, дожидаясь ответа).

N>(Да, оптимизации R14 про watermark на эту очередь не вспоминать — они тут не помогают.)

С портами не помогают, но почему не помогают "с любым случаем, где владелец длинной очереди синхронно с кем-то общается"? И почему — для этого любого другого случая — не вспоминать про watermark?

(для ясности контекста я позволил себе переставить цитируемое местами, надеюсь что без искажения смысла)
Re[8]: Go vs Erlang vs Elixir
От: neFormal Россия  
Дата: 09.02.17 19:10
Оценка:
Здравствуйте, netch80, Вы писали:

N>Или на ходу работы. Я не знаю, как ты этого не видишь, можно элементарным образом показать.


вот по ходу работы не видел, да.
бинарные строки уж точно не удаляются по ходу дела, это я прочувствовал в полной мере.
афаир в `erlang in anger` это всё описано хорошо.

N>Может, у тебя были просто короткоживущие процессы. У меня в нескольких крайне важных случаях был пул долгоживущих.


наоборот, в основном длинные. это постоянные коннекты юзеров с толстым state'ом и несколько важных подсистем не менее худых.
это при коротких незаметно, при длинных память улетает просто на ура. тем более у меня очень много работы было завязано как раз на строки. я наступил, наверное, на все грабли.
...coding for chaos...
Re[6]: Go vs Erlang vs Elixir
От: Evgeny.Panasyuk Россия  
Дата: 09.02.17 19:31
Оценка:
Здравствуйте, netch80, Вы писали:

N>То есть, если новых не поступит, время отработки пропорционально квадрату количества поступивших (точнее, каждый может подсчитать, чему равно N*(N-1)+(N-1)*(N-2)+(N-2)*(N-3)+..., но мне облом — асимпотически это равно N*N/2).


У тебя в формуле по сути сумма последовательности квадратов, что соответствует кубической сложности.
А должна быть сумма арифметической прогрессии (N + (N-1) + (N-2) + ...) — которая как раз квадратична.
Re[7]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 19:46
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

N>>То есть, если новых не поступит, время отработки пропорционально квадрату количества поступивших (точнее, каждый может подсчитать, чему равно N*(N-1)+(N-1)*(N-2)+(N-2)*(N-3)+..., но мне облом — асимпотически это равно N*N/2).


EP>У тебя в формуле по сути сумма последовательности квадратов, что соответствует кубической сложности.

EP>А должна быть сумма арифметической прогрессии (N + (N-1) + (N-2) + ...) — которая как раз квадратична.

Верно. Это я уже в спешке убегая писал.
The God is real, unless declared integer.
Re[7]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 09.02.17 20:44
Оценка:
Здравствуйте, meadow_meal, Вы писали:

_>А так не лечится?

_>http://www.rigtorp.se/latency.html
_>Или так:
_>https://github.com/jashmenn/rabbitmq-server/blob/master/src/rabbit_writer.erl

Посмотрел. Да, похоже, именно случай TCP это бы вылечило — за счёт залезания в недокументированные потроха реализации (что prim_inet, что port command это такие потроха). Это само по себе обидно, но, если бы у нас была фатальная необходимость досидеть на Erlang, наверняка так бы и сделали (и очень осторожно меняли базовый релиз).

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


Я тоже не в курсе. Но если Rabbit работает — значит, этот путь пока что работает...

N>>И подобные ситуации не только с TCP, а с любым случаем, где владелец длинной очереди синхронно с кем-то общается (то есть, дожидаясь ответа).

N>>(Да, оптимизации R14 про watermark на эту очередь не вспоминать — они тут не помогают.)

_>С портами не помогают, но почему не помогают "с любым случаем, где владелец длинной очереди синхронно с кем-то общается"? И почему — для этого любого другого случая — не вспоминать про watermark?


Потому что оптимизация с watermark жёстко рассчитана на вызов make_ref для одного запроса и получения ответа определённой структуры с этим ref. OK, не с любым, но в общем случае.
The God is real, unless declared integer.
Re[6]: Go vs Erlang vs Elixir
От: Cyberax Марс  
Дата: 09.02.17 23:06
Оценка:
Здравствуйте, netch80, Вы писали:

N>Хотя бы вот. Так вот, кодогенерация там очень слабая, если сравнивать с аналогами, где на заточку под процессоры с их возможностями ушло много человеко-лет. Но сделать выхлоп, например, в LLVM IR они не хотят — "у нас всё должно быть на Go".

Есть же gccgo, который не самый живой, но поддерживается и развивается.
Sapienti sat!
Re[3]: Go vs Erlang vs Elixir
От: Cyberax Марс  
Дата: 09.02.17 23:08
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

CK>Компилятор го вставляет вызовы runtime.Gosched перед некоторыми конструкциями, чтобы шедулер получал управление и мог прервать выполнение кода. В BEAM вытесняющая многозадачность, а в Go — кооперативная, со всеми вытекающими проблемами.

И какие же проблемы от этого вытекают? В Го можно послать тяжёлые графы объектов между потоками без всякого оверхеда, в отличие от Эрланга.

Да, насильная остановка потока — это фундаментально неправильная операция.
Sapienti sat!
Re[7]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 10.02.17 05:17
Оценка:
Здравствуйте, Cyberax, Вы писали:

N>>Хотя бы вот. Так вот, кодогенерация там очень слабая, если сравнивать с аналогами, где на заточку под процессоры с их возможностями ушло много человеко-лет. Но сделать выхлоп, например, в LLVM IR они не хотят — "у нас всё должно быть на Go".

C>Есть же gccgo, который не самый живой, но поддерживается и развивается.

_Пока_ есть.
The God is real, unless declared integer.
Re[5]: Go vs Erlang vs Elixir
От: sambl4 Россия  
Дата: 10.02.17 05:26
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

DD>>Почему Lisp? Вроде автор писал, что вдохновлялся Ruby в основном...


CK>А получился полноценный Lisp!


Закономерно получился :

Любая достаточно сложная программа на C или Фортране содержит заново написанную, неспецифицированную, глючную и медленную реализацию половины языка Common Lisp

Re[8]: Go vs Erlang vs Elixir
От: Cyberax Марс  
Дата: 10.02.17 07:29
Оценка:
Здравствуйте, netch80, Вы писали:

C>>Есть же gccgo, который не самый живой, но поддерживается и развивается.

N>_Пока_ есть.
По словам гугловодов, поддержка gccgo для них принципиальна. Ближайшие годы он будет развиваться, хотя у него циклы выпусков сильно длиннее, чем у Go.
Sapienti sat!
Re[6]: Go vs Erlang vs Elixir
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.02.17 13:32
Оценка:
Здравствуйте, netch80, Вы писали:

N>Хотя бы вот. Так вот, кодогенерация там очень слабая, если сравнивать с аналогами, где на заточку под процессоры с их возможностями ушло много человеко-лет. Но сделать выхлоп, например, в LLVM IR они не хотят — "у нас всё должно быть на Go".


Есть проект по реализации Go над LLVM. Насколько я понимаю, он пока очень сырой.

Кроме того, есть gccgo. Он тоже, насколько я понимаю, сыроват.
Re[9]: Go vs Erlang vs Elixir
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.02.17 13:35
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Тут согласен. Я думаю они все прекрасно понимали, и рассчитывали что вне циклов использовать select смысла нет, поэтому приоритетное событие никуда не убежит. Имело ли смысли усложнять язык ради метки приоритета -- . Они посчитали, что нет. С другой стороны в выше процитированной док-ии сказано, что выч. на канале идут в порядке следования их case'ов. И как бэ неявно приоритет будет отдаваться первому, наверное. В целом было логично, что если первый case готов -- управление ему, иначе рандомный выбор.


Нет, в спецификации сказано, что если в селекте готово несколько вариантов, то тот, который сработает, будет выбран с помощью генератора случайных чисел с равномерным распределением.
Re[9]: Go vs Erlang vs Elixir
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.02.17 13:39
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>>>Есть же gccgo, который не самый живой, но поддерживается и развивается.

N>>_Пока_ есть.
C>По словам гугловодов, поддержка gccgo для них принципиальна. Ближайшие годы он будет развиваться, хотя у него циклы выпусков сильно длиннее, чем у Go.

Я думаю, для них принципиально, чтобы было больше одной реализации языка. Если llvm обгонит gccgo, они могут его и забросить.
Re[11]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 10.02.17 13:47
Оценка:
Здравствуйте, Pzz, Вы писали:

N>>Не логично. Логично или строго по порядку, или по явно прописанным приоритетам (я бы предпочёл схему, как в DNS SRV записях — есть priority и есть weight).


Pzz>Я бы предпочел схему, в которой рантайм выберет первый попавшийся удобный ему case, потому что это дешевле всего. Только народ прочухает, в каком порядке рантайм выбирает варианты, и начнет использовать это для приоритезации.


FYI, правильно — "приоритизация"

Pzz>И если потом в рантайме алгоритм выбора варианта изменится, куча кода сломается. Поэтому они, назло всем, сделали случайный выбор.


Вот именно, что "назло всем" никогда не должно быть подходом проектирования языка. А в Go, похоже, такое любят — см. те же ошибки вместо предупреждений на неиспользованные импорты, или форсированная статическая сборка.

N>>И ещё обязательно должна быть возможность таймаута. Её сейчас тоже нет.

Pzz>Просто добавляем в select case, в который таймер тикает. Это ничем не хуже какого-то отдельного механизма для таймаута.

Хуже. Делать отдельную горутину для таймера... я понимаю, что они дешёвые, но это всё равно костыль.
Заметь, в Erlang таймеры — отдельные процессы, но receive всё равно имеет вариант after.
The God is real, unless declared integer.
Re[12]: Go vs Erlang vs Elixir
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.02.17 17:04
Оценка:
Здравствуйте, netch80, Вы писали:

N>>>И ещё обязательно должна быть возможность таймаута. Её сейчас тоже нет.

Pzz>>Просто добавляем в select case, в который таймер тикает. Это ничем не хуже какого-то отдельного механизма для таймаута.

N>Хуже. Делать отдельную горутину для таймера... я понимаю, что они дешёвые, но это всё равно костыль.

N>Заметь, в Erlang таймеры — отдельные процессы, но receive всё равно имеет вариант after.

Зачем отдельную гороутину? Таймер из стандартной библиотеки обходится одной гороутиной на всех.
Re: Go vs Erlang vs Elixir
От: Sharov Россия  
Дата: 10.02.17 17:40
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

На кворе вычитал:

I think conservative is the best description of Go's design. It doesn't bring anything new to the table
and ignores basically all advancements in programming language design from the last few decades.

Just look at their type system, which is basically worse than OCaml's in every way. OCaml supports
essentially the same sort of structural sub-typing, but without sacrificing type inference (what
Go has is too limited to honestly call "type inference") and with well-supported and well-implemented
generics. And don't get me started on how variants actually make sense for error handling unlike Go's approach!

Moreover, all this technology (like how to implement those generics safely and efficiently) is
well-understood and well-documented in academic papers which I suspect the Go designers largely
ignored. Instead, they couldn't figure out how to implement generics efficiently and so decided
to sacrifice both expressiveness and safety to the altar of compiler simplicity. Much better
to have every end-user pay a small amount than to pay a larger cost once, in the compiler!

All this and OCaml still manages fast compile times and good performance. But obviously,
unlike Go, it's not a practical language, so they couldn't have considered it.

The Go creators liked C--about as far from functional as possible--so they wrote a C 2.0.
Except with garbage collection. Because C is obviously a perfect programming language except for being too low-level.


Где-то тут.
Кодом людям нужно помогать!
Re: Go vs Erlang vs Elixir
От: alex_public  
Дата: 10.02.17 23:46
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

CK>Может кто-нибудь объяснить, почему люди считают что Go подходит для concurrency и сервисов, хотя там нет нормального планировщика (любая горутина может неотдавать управление неограничено долго), общая память и глобальный GC, невозможно нормально остановить горутину, нет нормальной обработки ошибок?


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

CK>Самое главное, есть же нормальная алтернатива — Erlang/Elixir + OTP.


Эрланг немного из другой области — динамических языков. )
Re[12]: Go vs Erlang vs Elixir
От: meadow_meal  
Дата: 11.02.17 06:44
Оценка:
Здравствуйте, netch80, Вы писали:

N>Заметь, в Erlang таймеры — отдельные процессы, но receive всё равно имеет вариант after.


Все же erlang:send_after/3 и erlang:start_timer/3 не используют отдельные процессы. Модуль timer — да, но его и используют редко.
Re[6]: Go vs Erlang vs Elixir
От: Masterspline  
Дата: 11.02.17 17:39
Оценка:
> Чтобы перебрать всю очередь и перейти в ожидание, ему нужно прошерстить N-1 сообщение

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

Вариант номер два: делаешь отправку в отдельной корутине, туда же придет и ответ по tcp, и там не будет такой очереди.

Я это к тому, что решения этой задачи существуют, другой вопрос, насколько это решение тебе подойдет.
Re[7]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 11.02.17 17:44
Оценка:
Здравствуйте, Masterspline, Вы писали:

>> Чтобы перебрать всю очередь и перейти в ожидание, ему нужно прошерстить N-1 сообщение


M>Вариант номер раз: перед чтением первого сообщения, вычитываешь все в локальный кеш и затем работаешь с кешем. Кстати, так ты сможешь и приоритеты реализовать.


Если за это время навалят ещё сообщений — не сработает. На практике именно так и происходило.

M>Вариант номер два: делаешь отправку в отдельной корутине, туда же придет и ответ по tcp, и там не будет такой очереди.


Проходили. Не работает. Сам догадаешься, почему?

M>Я это к тому, что решения этой задачи существуют, другой вопрос, насколько это решение тебе подойдет.


Вариант по ссылкам от meadow_meal, скорее всего, сработает, да. Если наплевать на идеологическую правильность влезания в недокументированные потроха. Что мне, собственно, в нём и не нравится (и не только мне). Сработает потому, что в нём вообще исключён просмотр вперёд за синхронным ответом.
Твои варианты — нет и никак.
The God is real, unless declared integer.
Re[8]: Go vs Erlang vs Elixir
От: neFormal Россия  
Дата: 11.02.17 19:27
Оценка:
Здравствуйте, netch80, Вы писали:

M>>Вариант номер раз: перед чтением первого сообщения, вычитываешь все в локальный кеш и затем работаешь с кешем. Кстати, так ты сможешь и приоритеты реализовать.

N>Если за это время навалят ещё сообщений — не сработает. На практике именно так и происходило.

вообще в энларге это используют. вычитывают весь мейлбокс и обрабатывают сразу.
но это подходит не для всех задач.
...coding for chaos...
Re[9]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 11.02.17 19:47
Оценка:
Здравствуйте, neFormal, Вы писали:

M>>>Вариант номер раз: перед чтением первого сообщения, вычитываешь все в локальный кеш и затем работаешь с кешем. Кстати, так ты сможешь и приоритеты реализовать.

N>>Если за это время навалят ещё сообщений — не сработает. На практике именно так и происходило.
F>вообще в энларге это используют. вычитывают весь мейлбокс и обрабатывают сразу.

Да-да. Например, gen_server2 уже хрестоматийный.

F>но это подходит не для всех задач.


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

Ну и само его применение в качестве хака по исправлению отдельных симптомов вместо лечения причины — повод грустить.

Мы ещё применяли передачу экстренных управляющих сообщений полями в ETS. Например, на сервис запускалось два gen_server — один для основной нагрузки и один контрольно-управляющий. При этом контрольно-управляющий складывал предписания нагрузочному исполнителю в ETS, а нагрузочный заглядывал туда раз в N обработанных сообщений (N было от 100 до 1000) и ещё получал предписания заглянуть от таймера (который тупо слал что-то раз в секунду).
Но перевести всё управляющее общение на ETS было в принципе невозможно, так же как и полечить управляемость релейного сервера, который на один запрос к gen_server может создать некоторое количество (пусть даже с коэффициентом размножения сильно меньше 1) аналогичных запросов к другим.
The God is real, unless declared integer.
Re[8]: Go vs Erlang vs Elixir
От: Masterspline  
Дата: 12.02.17 05:31
Оценка:
>>> Чтобы перебрать всю очередь и перейти в ожидание, ему нужно прошерстить N-1 сообщение

M>>Вариант номер раз: перед чтением первого сообщения, вычитываешь все в локальный кеш и затем работаешь с кешем. Кстати, так ты сможешь и приоритеты реализовать.


N>Если за это время навалят ещё сообщений — не сработает. На практике именно так и происходило.


С тем, что за время ожидания ответа по tcp тебе могут прийти новые сообщения мне все понятно, но вот с асимптотикой N^2 совсем не понятно.

Если при обработке каждого сообщения тебе придется из очереди выгребать N сообщений, то очередь будет расти (обработали одно сообщение, а пришло N). Больше похоже на линейную сложность.
Re[9]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 12.02.17 06:30
Оценка:
Здравствуйте, Masterspline, Вы писали:

>>>> Чтобы перебрать всю очередь и перейти в ожидание, ему нужно прошерстить N-1 сообщение


M>>>Вариант номер раз: перед чтением первого сообщения, вычитываешь все в локальный кеш и затем работаешь с кешем. Кстати, так ты сможешь и приоритеты реализовать.


N>>Если за это время навалят ещё сообщений — не сработает. На практике именно так и происходило.


M>С тем, что за время ожидания ответа по tcp тебе могут прийти новые сообщения мне все понятно, но вот с асимптотикой N^2 совсем не понятно.


M>Если при обработке каждого сообщения тебе придется из очереди выгребать N сообщений, то очередь будет расти (обработали одно сообщение, а пришло N). Больше похоже на линейную сложность.


Снова теряешь контекст.
Линейная сложность возникает в ситуации, когда данный процесс не требует синхронных ответов. Как именно он это делает — тут уже неважно. Тогда цикл работы — выхватил сообщение из головы(!) очереди (O(1) на сообщение на это действие), отослал ответ, забыл.
Теперь пусть у тебя есть необходимость на каждое сообщение что-то передавать кому-то другому (это может быть процесс, или порт, как в случае gen_tcp) и ждать ответ. Предположим, у тебя есть постоянный темп сообщений. В какой-то момент выгреб всё, это N сообщений. Начинаешь отрабатывать, пока ты отработал K сообщений, в очереди уже ждёт K*p, где p — некоторое число, соответствующее темпам поступлений и расчистки. И на каждое отработанное следующее тебе нужно потратить времени пропорционально K*p для того, чтобы синхронный ответ (другого сервера, порта) извлечь из _конца_ очереди, перебрав все, что были перед ним. Закончил разборку N сообщений — на входе уже стоит N*p. И снова возвращаемся к той формуле, что была раньше, которая и даёт квадрат.

И поэтому надёжно работает только один метод — не пытаться вычитывать никого в обход головы очереди.
The God is real, unless declared integer.
Re[10]: Go vs Erlang vs Elixir
От: Masterspline  
Дата: 12.02.17 07:03
Оценка:
Мой алгоритм такой: вычитываешь все сообщения из очереди и кладешь их в кеш. Обрабатываешь первое сообщение из кеша. Вычитываешь, что накопилось снова в кеш. Обрабатываешь из головы кеша. Тогда в очереди (невычитанной) будет накапливаться порядка p сообщений, причем p около 1, иначе реальная очередь, которая в кеше будет расти (в результате сложность становится линейной). При этом, насколько я понимаю, при обработке сообщения, требующего синхронного ответа, нужно будет перебрать только невычитанные сообщения (те самые, которых ~p). Суть с том, чтобы перед обработкой каждого сообщения считывать все накопившиеся сообщения в кеш (если мы сейчас говорим про Ерланг, то не в курсе, как там это делать, т.к. не люблю функциональщину с ее искусственными ограничениями).
Re[11]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 12.02.17 07:20
Оценка:
Здравствуйте, Masterspline, Вы писали:

M>Мой алгоритм такой: вычитываешь все сообщения из очереди и кладешь их в кеш. Обрабатываешь первое сообщение из кеша. Вычитываешь, что накопилось снова в кеш. Обрабатываешь из головы кеша. Тогда в очереди (невычитанной) будет накапливаться порядка p сообщений, причем p около 1, иначе реальная очередь, которая в кеше будет расти (в результате сложность становится линейной). При этом, насколько я понимаю, при обработке сообщения, требующего синхронного ответа, нужно будет перебрать только невычитанные сообщения (те самые, которых ~p). Суть с том, чтобы перед обработкой каждого сообщения считывать все накопившиеся сообщения в кеш (если мы сейчас говорим про Ерланг, то не в курсе, как там это делать, т.к. не люблю функциональщину с ее искусственными ограничениями).


Вот ядро gen_call — синхронного вызова другого процесса, отрабатывающего интерфейс gen_server/gen_fsm:

    try erlang:monitor(process, Process) of
        Mref ->
            catch erlang:send(Process, {Label, {self(), Mref}, Request},
                  [noconnect]),
            receive
                {Mref, Reply} ->
                    erlang:demonitor(Mref, [flush]),
                    {ok, Reply};
                {'DOWN', Mref, _, _, noconnection} ->
                    Node = get_node(Process),
                    exit({nodedown, Node});
                {'DOWN', Mref, _, _, Reason} ->
                    exit(Reason)
            after Timeout ->
                    erlang:demonitor(Mref, [flush]),
                    exit(timeout)
            end
<... скипнул ситуации "нода лежит" и т.п.>


Здесь явный receive. Чтобы сделать по твоей схеме, надо заменить это на попытку вычитать вначале из кэша. Мы говорим о библиотечной функции (которую вызвать, кстати, может другое действие, которое вроде бы не относится к внешнему взаимодействию — но оно так сделано в текущем OTP). Значит, уже нужна хаченая OTP, чтобы это гарантированно работало на всех уровнях.

Далее, аналогично в gen_server и прочих придётся вместо его receive на следующее сообщение делать вычитку из этого кэша. И ещё в 100500 местах.

Да, это всё не имеет отношения к тому, функциональный язык или нет. Зато прямое — к рантайму. Если ты вместо стандартной очереди рантайма делаешь свои — будь готов переделать на них всё. (Чуть более, чем всё, потому что есть ещё куча стороннего софта, который не в курсе твоих заморочек.)
The God is real, unless declared integer.
Re[10]: Go vs Erlang vs Elixir
От: meadow_meal  
Дата: 12.02.17 09:08
Оценка:
Здравствуйте, netch80, Вы писали:

N>Линейная сложность возникает в ситуации, когда данный процесс не требует синхронных ответов. Как именно он это делает — тут уже неважно. Тогда цикл работы — выхватил сообщение из головы(!) очереди (O(1) на сообщение на это действие), отослал ответ, забыл.

N>Теперь пусть у тебя есть необходимость на каждое сообщение что-то передавать кому-то другому (это может быть процесс, или порт, как в случае gen_tcp) и ждать ответ. Предположим, у тебя есть постоянный темп сообщений. В какой-то момент выгреб всё, это N сообщений. Начинаешь отрабатывать, пока ты отработал K сообщений, в очереди уже ждёт K*p, где p — некоторое число, соответствующее темпам поступлений и расчистки. И на каждое отработанное следующее тебе нужно потратить времени пропорционально K*p для того, чтобы синхронный ответ (другого сервера, порта) извлечь из _конца_ очереди, перебрав все, что были перед ним. Закончил разборку N сообщений — на входе уже стоит N*p. И снова возвращаемся к той формуле, что была раньше, которая и даёт квадрат.

N>И поэтому надёжно работает только один метод — не пытаться вычитывать никого в обход головы очереди.


Вообще по этой задаче у нас есть неконтролируемый входной поток данных и их обработка, и при этом в общем случае отсутствуют какие-либо гарантии, что обработка происходит быстрее, чем поступление данных на вход. То есть проблема уже заложена в постановку задачи. Selective receive это возможный катализатор (а если используется gen:call, то и не факт), а никак не причина. Рано или поздно очередь будет расти, а это всегда проблема (даже если не дойдет до OOM, то те же control messages будут приходить слишком поздно и т.п.).

Буферный процесс для входящего потока мог бы решить проблему. Он бы просто складывал сообщения в буфер, а мы бы загребали их у него пачками (посылая асинхронное уведомление о готовности обработать не более N сообщений). В итоге наш отправляющий процесс имеет контролируемый входной поток сообщений. Что до буферного, то придется решить, что делать при переполнении — но здесь мы хотя бы это сами контролируем. Переполнение может произойти в любом случае, нельзя просто надеяться что мы отправляем быстрее чем получаем, и selective receive здесь не виноват.

Вообще, здесь на rsdn уже несколько раз читал (в сообщениях разных людей), что медленный selective receive — это родовая травма эрланга и чуть ли не повод его не использовать. Мне это кажется сомнительным, там, где selective receive приводит к проблемам, проблемы возникли бы (чуть позже, но со всей вероятностью) и имей selective receive константную сложность. Просто неконтролируемый входной поток надо делать контролируемым.

Сейчас пробежался глазами, кажется, то же самое предложил Masterspline в этом сообщении:

M>Вариант номер два: делаешь отправку в отдельной корутине, туда же придет и ответ по tcp, и там не будет такой очереди.


N>Проходили. Не работает. Сам догадаешься, почему?


Вот значит я не догадался. Почему? (На случай если я неверно понял, что именно предложил Masterspline, и это совсем другое, то меня конечно больше интересуют недостатки моего собственного предложения)
Re[12]: Go vs Erlang vs Elixir
От: chaotic-kotik  
Дата: 12.02.17 10:11
Оценка:
Здравствуйте, netch80, Вы писали:


N>Но описанные факторы дают квадратичную зависимость. И из них любое даже небольшое внутреннее переполнение приводит к лавинному эффекту: временная точка затора начинает разбухать.


N>В последнем из проектов, где я столкнулся с этим, цифры выглядели примерно так: нагрузка растёт ровно до достижения примерно 25K сообщений в секунду. (В разные пробы были заметно разные цифры, от 15K до 30K, и это тоже показательно.) Пока среднее значение длины очереди релейного процесса — до пары десятков сообщений, всё работает. Но чем выше, тем больше вероятность того, что очередь скакнёт до сотен просто из-за того, что шедулинг не успевает переключать процессы; это чисто стохастический процесс. По достижению этого уровня (сотни сообщений в очереди) релеинг фактически останавливается, снижая скорость, причём до чудовищно низких величин (когда 3K, а когда и просто сотни сообщений в секунду). Далее срабатывал регулятор нагрузки в тесте и снижал её, но привести систему к исходному состоянию можно было только добившись снижения темпа (или полной остановки) до того, что очередь на релейном процессе падала почти до нуля. Тогда его скорость восстанавливалась.


Это похоже на network congestion очень сильно. Без backpressure это никак не решить. Даже с разными очердями, рано или поздно, наступит момент когда без backpressure это перестанет работать.
Re[12]: Go vs Erlang vs Elixir
От: meadow_meal  
Дата: 12.02.17 10:32
Оценка:
Здравствуйте, netch80, Вы писали:

Спасибо за подробный ответ, это очень интересно. Не сразу, но в итоге понял, в чем я не прав.
Re[13]: Go vs Erlang vs Elixir
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 12.02.17 10:55
Оценка:
Здравствуйте, chaotic-kotik, Вы писали:

N>>В последнем из проектов, где я столкнулся с этим, цифры выглядели примерно так: нагрузка растёт ровно до достижения примерно 25K сообщений в секунду. (В разные пробы были заметно разные цифры, от 15K до 30K, и это тоже показательно.) Пока среднее значение длины очереди релейного процесса — до пары десятков сообщений, всё работает. Но чем выше, тем больше вероятность того, что очередь скакнёт до сотен просто из-за того, что шедулинг не успевает переключать процессы; это чисто стохастический процесс. По достижению этого уровня (сотни сообщений в очереди) релеинг фактически останавливается, снижая скорость, причём до чудовищно низких величин (когда 3K, а когда и просто сотни сообщений в секунду). Далее срабатывал регулятор нагрузки в тесте и снижал её, но привести систему к исходному состоянию можно было только добившись снижения темпа (или полной остановки) до того, что очередь на релейном процессе падала почти до нуля. Тогда его скорость восстанавливалась.


CK>Это похоже на network congestion очень сильно. Без backpressure это никак не решить. Даже с разными очердями, рано или поздно, наступит момент когда без backpressure это перестанет работать.


Спасибо, кэп. Да, наступит. Вопрос в том, что именно будет, когда оно наступит.
Если зависимость времени обработки одного сообщения от длины очереди отсутствует или не выходит за фиксированные пределы, и можно говорить про O(1), регулировка работает беспроблемно. Например, мы устанавливаем, что сумма очередей в цепочке после входного процесса не превышает 20K, а каждый из этих процессов в цепочке шлёт обновление своего статуса на 1000 обработанных сообщений или раз в секунду. Тогда при превышении этого порога мы просто прекратим принимать, оно пойдёт рассасываться, и как только упадёт ниже порога — снова начнём приём. (В случае TCP, для этого можно, например, с момента видения превышения перестать обновлять active у gen_tcp порта, а для возобновления послать ему что-то вроде {active,10}.)
Если же описанное квадратичное — то будет картина, как я описал в предыдущем сообщении. N сообщений отрабатывается за время T, а 2*N — за 4*T. Если ожидаешь скорости N/T, нужно немедленно останавливать приём, как только очередь достигла N, или даже числа меньшего, чем N, потому что пока до приёмника извне дойдёт команда остановиться, он успеет ещё прислать неизвестно сколько. А вот насколько меньше — надо вычислять по свойствам реальной системы. И всё равно колебания потока приведут к тому, что зашкалы будут, и систему будет клинить...
The God is real, unless declared integer.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.