Технически, почему процессы в Erlang более эффективны, чем потоки ОС?

Эрланг Характеристики

Из Erlang Programming (2009):

Эрлангский параллелизм быстрый и масштабируемый. Его процессы легки в том, что виртуальная машина Erlang не создает поток ОС для каждого созданного процесса. Они создаются, планируются и обрабатываются в виртуальной машине независимо от базовой операционной системы. В результате время создания процесса составляет порядка микросекунд и не зависит от числа одновременно существующих процессов. Сравните это с Java и С#, где для каждого процесса создается базовый поток ОС: вы получите несколько очень конкурентоспособных сравнений, причем Erlang значительно превосходит оба языка.

Из ориентированного на параллелизм программирования в Erlang (pdf) (слайды) (2003):

Мы отмечаем, что время, необходимое для создания процесса Эрланга, составляет от 1 мкс до 2500 процессов; после этого он увеличивается примерно до 3 мкс до 30 000 процессов. Производительность Java и С# показана в верхней части рисунка. Для небольшого числа процессов создание процесса занимает около 300 мкс. Создание более двух тысяч процессов невозможно.

Мы видим, что для 30 000 процессов время отправки сообщения между двумя процессами Erlang составляет около 0,8 мкс. Для С# это занимает около 50 мкс на сообщение, до максимального количества процессов (которое было около 1800 процессов). Java была еще хуже: на 100 процессов приходилось около 50 мкс на сообщение, после чего она быстро увеличивалась до 10 мс на сообщение, когда было около 1000 Java-процессов.

Мои мысли

Я не совсем понимаю, с технической точки зрения, почему процессы Эрланга намного более эффективны в порождении новых процессов и имеют гораздо меньшие объемы памяти на процесс. И ОС, и Erlang VM должны выполнять планирование, переключение контекста и отслеживать значения в регистрах и так далее...

Просто почему потоки ОС не реализуются так же, как процессы в Erlang? Должны ли они поддерживать что-то большее? И зачем им больше памяти? И почему у них медленнее нерест и общение?

Технически, почему процессы в Erlang более эффективны, чем потоки ОС, когда речь идет о порождении и коммуникации? И почему потоки в ОС не могут быть реализованы и управляться так же эффективно? И почему потоки ОС занимают больше места в памяти, а также медленнее порождают и общение?

Больше чтения

Ответ 1

Существует несколько факторов:

  • Процессы Erlang не являются процессами ОС. Они реализованы Erlang VM с использованием облегченной модели совместного использования потоков (упреждающей на уровне Erlang, но под контролем совместной запланированной среды исполнения). Это означает, что переключить контекст намного дешевле, потому что они только переключаются на известные контролируемые точки и, следовательно, не должны сохранять все состояние ЦП (нормальные, регистры SSE и FPU, отображение адресного пространства и т.д.).
  • Процессы Erlang используют динамически распределенные стеки, которые начинаются очень маленькими и растут по мере необходимости. Это позволяет нереститься на многие тысячи - даже миллионы - процессов Erlang, не всасывая всю доступную оперативную память.
  • Erlang раньше был однопоточным, а это означало, что не требовалось обеспечивать безопасность потоков между процессами. Теперь он поддерживает SMP, но взаимодействие между процессами Erlang на одном и том же планировщике/ядре все еще очень легкое (есть отдельные очереди очередей на ядро).

Ответ 2

После еще нескольких исследований я нашел презентацию Джо Армстронга.

Из Erlang - программное обеспечение для параллельного мира (презентация) (в 13 минут):

[Erlang] - это параллельный язык - я имею в виду, что потоки являются частью языка программирования, они не принадлежат операционной системе. Это действительно неправильно с языками программирования, такими как Java и С++. Это потоки не на языке программирования, потоки - это что-то в операционной системе - и они наследуют все проблемы, которые они имеют в операционной системе. Одной из проблем является гранулярность системы управления памятью. Управление памятью в операционной системе защищает целые страницы памяти, поэтому наименьший размер, который может быть потоком, является наименьшим размером страницы. Это на самом деле слишком большое.

Если вы добавляете больше памяти на свой компьютер - у вас есть такое же количество бит, которое защищает память, так что гранулярность таблиц страниц увеличивается. - в итоге вы используете, скажем, 64 КБ для процесс, который, как вы знаете, работает в нескольких сотнях байт.

Я думаю, что это ответы, если не все, по крайней мере несколько моих вопросов

Ответ 3

Я реализовал сопрограммы в ассемблере и измерял производительность.

Переключение между сопроцессами, процессами a.k.a. Erlang, занимает около 16 инструкций и 20 наносекунд на современном процессоре. Кроме того, вы часто знаете процесс, к которому вы переключаетесь (например: процесс, получающий сообщение в своей очереди, может быть реализован как прямая передача от вызывающего процесса к процессу приема), поэтому планировщик не вступает в игру, делая это операция O (1).

Чтобы переключить потоки ОС, требуется около 500-1000 наносекунд, потому что вы обращаетесь к ядру. Планировщик потоков ОС может работать в режиме O (log (n)) или O (log (log (n))), который станет заметным, если у вас есть десятки тысяч или даже миллионы потоков.

Следовательно, процессы Erlang быстрее и масштабируются, потому что и основная операция переключения выполняется быстрее, а планировщик работает менее часто.

Ответ 4

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

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


Другой способ понять разницу - это. Предположим, что вы собираетесь написать реализацию Erlang поверх JVM (не особенно сумасшедшего предложения), тогда вы сделаете каждый процесс Erlang объектом с каким-то состоянием. Тогда у вас будет пул экземпляров Thread (как правило, в зависимости от количества ядер в вашей хост-системе, что настраиваемый параметр в реальном времени Erlang BTW), которые запускают процессы Erlang. В свою очередь, это будет распространять работу, которая должна быть выполнена через доступные реальные ресурсы системы. Это довольно аккуратный способ делать что-то, но полностью полагается на то, что каждый процесс Erlang не очень-то работает. Это нормально, конечно. Эрланг структурирован, чтобы не требовать, чтобы эти отдельные процессы были тяжеловесными, поскольку это общий ансамбль из них, которые выполняют программу.

Во многих отношениях реальная проблема является терминологией. То, что Эрланг называет процессами (и которые сильно соответствуют одному и тому же понятию в CSP, CCS и, в частности, π-исчислении), просто не совпадают с вещами, в которых языки с C-наследием (включая С++, Java, С# и многие другие) называют процесс или поток. Есть несколько сходств (все связаны с некоторыми понятиями параллельного выполнения), но определенно нет эквивалентности. Поэтому будьте осторожны, когда кто-то скажет вам "процесс"; они могут понимать это как нечто совершенно иное...

Ответ 5

Я думаю, что Jonas хотел, чтобы некоторые числа сравнивали потоки ОС с процессами Erlang. Автор программирования Erlang, Joe Armstrong, некоторое время назад проверял масштабируемость нереста процессов Erlang на потоки ОС. Он написал простой веб-сервер в Erlang и протестировал его против многопоточного Apache (так как Apache использует потоки ОС). Там старый веб-сайт с данными, относящимися к 1998 году. Мне удалось найти этот сайт ровно один раз. Поэтому я не могу предоставить ссылку. Но информация там. Основной момент исследования показал, что Apache превысил 8 тыс. Процессов, в то время как его ручная работа с сервером Erlang обрабатывала процессы 10K +.

Ответ 6

Поскольку интерпретатору Erlang приходится только беспокоиться о себе, OS может беспокоиться о многом.

Ответ 7

Одна из причин заключается в том, что процесс erlang создается не в ОС, а в виртуальной машине evm (erlang), поэтому стоимость меньше.

Ответ 8

Это радикально, я знаю, но потом кто-то забыл упомянуть о виртуальной машине.