Erlang всегда копирует сообщения между процессами на одном и том же node?

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

Передача сообщений с нулевой копией реализована вообще в Erlang? Между узлами он, очевидно, не может быть реализован как таковой, но как быть между процессами на одном и том же node? Этот вопрос связан.

Ответ 1

Я не думаю, что ваше утверждение верное - глубокое копирование межпроцессных сообщений не является узким местом в Erlang, а с установкой/настройкой VM по умолчанию это именно то, что делают все системы Erlang.

Кучи процессов Erlang полностью отделены друг от друга, и очередь сообщений находится в куче процесса, поэтому сообщения должны быть скопированы. Это справедливо также для передачи данных в таблицы ETS и из них, поскольку их данные хранятся в отдельной области выделения из кучи процессов.

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

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

Как отметил Николаус Градвохль, для виртуальной машины был экспериментальный гибридный режим кучи, который позволил провести разделение между процессами и разрешить передачу сообщений с нулевой копией. Это, по-моему, не было особенно многообещающим экспериментом - он требует дополнительной блокировки и усложняет существующую способность процессов самостоятельно собирать мусор. Таким образом, не только копирование межпроцессных сообщений не является обычным узким местом в системах Erlang, что позволяет фактически снизить производительность.

Ответ 2

AFAIK был/является экспериментальной поддержкой для передачи сообщений с нулевой копией в erlang с использованием -shared или -hybrid modell. Я прочитал сообщение в блоге в 2009 году, утверждая, что он сломан на smp-машинах, но я понятия не имею о текущем состоянии

Ответ 3

Как уже упоминалось здесь, и в других вопросах текущие версии Erlang в основном копируют все, кроме больших двоичных файлов. В более старые времена до SMP было возможно не копировать, а передавать ссылки. Хотя это привело к очень быстрой передаче сообщений, это создало другие проблемы в реализации, в первую очередь это сделало сборку мусора более сложной и сложной реализацией. Я думаю, что сегодня передача ссылок и совместное использование данных может привести к чрезмерной блокировке и синхронизации, что, конечно же, не является хорошей вещью.

Ответ 4

Я написал принятый ответ на этот другой вопрос, на который вы ссылаетесь, и в нем я даю вам прямой указатель на эту строку кода:

message = copy_struct(message, msize, &hp, &bp->off_heap);

Это функция, вызываемая, когда система времени выполнения Erlang должна отправить сообщение, и она не находится внутри какого-либо "if", что может привести к ее пропуску. Итак, насколько я могу судить, ответ "да, он всегда копируется". (Это не совсем верно - есть "если", но, похоже, он имеет дело с исключительными случаями, а не с обычным путем прохождения кода.)

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

Я не знаю, почему вы рассматриваете узкое место на 10 ГБ/сек. Ничто, кроме регистров или кэша CPU, не ускоряется в компьютере, и такие воспоминания малы, поэтому они являются своего рода узким местом. Кроме того, идея нулевой копии, которую вы предлагаете, потребует блокировки в случае передачи сообщений с несколькими процессорами в многоядерной системе, что также является узким местом. Мы уже платим штраф за блокировку один раз в этой функции, чтобы скопировать сообщение в другую очередь сообщений процесса; зачем платить позже, когда этот процесс приближается к чтению сообщения?

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