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

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

Из Erlang Programming (2009):

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

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

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

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

Мои мысли

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

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

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

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

7 ответов

Решение

Есть несколько способствующих факторов:

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

Другие вопросы по тегам