Технически, почему процессы в Erlang более эффективны, чем потоки ОС?
Эрланг характеристики
С Эрланг Программирования (2009):
параллелизм Erlang является быстрым и масштабируемым. Его процессы являются легкими в том, что виртуальная машина Erlang не создает поток ОС для каждого созданного процесса. Они создаются, планируются и обрабатываются в виртуальной машине независимо от базовой операционной системы. В результате время создания процесса составляет порядка микросекунд и не зависит от количества параллельно существующие процессы. Сравните это с Java и C#, где для каждого процесса создается базовый поток ОС: вы получите некоторые очень конкурентные сравнения, причем Erlang значительно превосходит оба языка.
С параллелизм ориентированное программирование в Erlang (pdf)(слайды) (2003):
мы наблюдаем, что время, необходимое для создания процесса Эрланга, является постоянным 1μs до 2500 процессов; после этого он увеличивается до 3µs до 30 000 процессов. Производительность Java и C# показана в верхней части рисунка. Для небольшого количества процессов требуется около 300 мкс, чтобы создать процесс. Создание более двух тысяч процессов невозможно.
мы видим, что для до 30 000 процессов время отправки сообщения между двумя процессами Erlang составляет около 0,8 МКС. Для C# это занимает около 50 мкс на сообщение, до максимального количества процессов (который был около 1800 процессов). Ява было еще хуже, для процесса до 100 потребовалось около 50 мкс на сообщение, после чего он быстро увеличился до 10 МС на сообщение, когда было около 1000 процессов Java.
мои мысли
Я не совсем понимаю технически, почему процессы Erlang настолько эффективны в создании новых процессов и имеют гораздо меньшие следы памяти для каждого процесса. Как ОС, так и Erlang VM должны выполнять планирование, переключение контекста и отслеживать значения в регистрах и так далее...
просто почему потоки ОС не реализованы так же, как процессы в Erlang? Они должны поддерживать что-то еще? И зачем им нужен больший объем памяти? А почему у них медленнее нерест и общение?
технически, почему процессы в Erlang более эффективны, чем потоки ОС, когда дело доходит до нереста и связи? И почему потоки в ОС не могут быть реализованы и управляться одинаково эффективно? И почему потоки ОС имеют больший объем памяти, а также более медленное размножение и связь?
чтение
7 ответов:
есть несколько факторов:
- процессы Erlang не являются процессами ОС. Они реализуются виртуальной машиной Erlang с использованием облегченной модели совместной потоковой передачи (упреждающей на уровне Erlang, но под контролем совместно запланированной среды выполнения). Это означает, что гораздо дешевле переключать контекст, потому что они переключаются только в известных, контролируемых точках и поэтому не должны сохранять все состояние процессора (обычный, регистры SSE и FPU, адрес отображение пространства и т. д.).
- процессы Erlang используют динамически распределенные стеки, которые начинаются очень маленькими и растут по мере необходимости. Это позволяет порождать многие тысячи - даже миллионы-процессов Erlang без всасывания всей доступной оперативной памяти.
- Erlang раньше был однопоточным, что означает, что не требовалось обеспечивать безопасность потоков между процессами. Теперь он поддерживает SMP, но взаимодействие между процессами Erlang на одном планировщике/ядре по-прежнему очень легкий (есть отдельные очереди запуска на ядро).
после еще нескольких исследований я нашел презентацию Джо Армстронга.
с Erlang-программное обеспечение для параллельного мира (презентация) (по 13 минут):
[Erlang] является параллельным языком – под этим я подразумеваю, что потоки являются частью языка программирования, они не принадлежат операционной системе. Это действительно то, что не так с языками программирования, такими как Java и C++. Это потоки не на языке программирования, потоки что – то в операционной системе-и они наследуют все проблемы, которые у них есть в операционной системе. Одной из проблем является детализация системы управления памятью.управление памятью в операционной системе защищает целые страницы памяти, поэтому самый маленький размер, который может быть потоком, - это самый маленький размер страницы.это на самом деле слишком большой.
если вы добавляете больше памяти к вашей машине – вы имеете такое же количество биты, которые защищают память, поэтому детализация таблиц страниц повышается -вы в конечном итоге используете, скажем, 64kB для процесса, который вы знаете, работает в несколько сотен байт.
Я думаю, что он отвечает если не на все, то хотя бы на несколько моих вопросов
я реализовал сопрограммы в ассемблере и измерил производительность.
переключение между сопрограммами, а также процессами Erlang, занимает около 16 инструкций и 20 наносекунд на современном процессоре. Кроме того, вы часто знаете процесс, на который вы переключаетесь (пример: процесс, получающий сообщение в своей очереди, может быть реализован как прямая передача от вызывающего процесса к принимающему процессу), поэтому планировщик не вступает в игру, что делает его O(1) операция.
для переключения потоков ОС требуется около 500-1000 наносекунд, потому что вы вызываете ядро. Планировщик потоков ОС может работать в O(log(n)) или O(log(log (n))) время, которое начнет быть заметным, если у вас есть десятки тысяч или даже миллионы потоков.
таким образом, процессы Erlang быстрее и масштабируются лучше, потому что как основная операция переключения быстрее, так и планировщик работает реже.
процессы Эрланга соответствуют (приблизительно)зеленые нити на других языках; нет принудительного разделения ОС между процессами. (Там вполне может быть языковое разделение, но это меньшая защита, несмотря на то, что Эрланг делает лучшую работу, чем большинство.) Потому что они гораздо легче, они могут быть использованы гораздо более широко.
потоки ОС, с другой стороны, могут быть просто запланированы на разных ядрах процессора и (в основном) способны поддержка независимой обработки с привязкой к процессору. Процессы ОС похожи на потоки ОС,но с гораздо более сильным разделением ОС. Цена этих возможностей заключается в том, что потоки ОС и (тем более) процессы стоят дороже.
другой способ понять различие заключается в следующем. Предположим, вы собираетесь написать реализацию Erlang поверх JVM (не особенно сумасшедшее предложение), тогда вы сделаете каждый процесс Erlang объектом с некоторым состоянием. Тогда у вас было бы пул экземпляров потоков (обычно размером в соответствии с количеством ядер в вашей хост-системе; это настраиваемый параметр в реальном времени выполнения Erlang BTW), который запускает процессы Erlang. В свою очередь, это позволит распределить работу, которая должна быть выполнена, по имеющимся реальным системным ресурсам. Это довольно аккуратный способ делать вещи, но полагается совершенно о том, что каждый отдельный процесс Эрланга не делает очень много. Это нормально, конечно; Erlang структурирован, чтобы не требовать их отдельные процессы должны быть тяжеловесными, так как это общий ансамбль из них, которые выполняют программу.
во многих отношениях реальная проблема заключается в терминологии. Вещи, которые Эрланг называет процессами (и которые сильно соответствуют одной и той же концепции в CSP, CCS и особенно π-исчислении), просто не совпадают с тем, что языки с наследием C (включая C++, Java, C# и многие другие) называют процессом или потоком. Есть некоторые сходства (все они включают некоторое понятие параллельного выполнения), но определенно нет эквивалентности. Поэтому будьте осторожны, когда кто-то говорит вам "процесс"; они могут понять, что это означает что-то совершенно другое...
Я думаю, что Джонас хотел некоторые цифры по сравнению потоков ОС с процессами Erlang. Автор программирования Erlang, Джо Армстронг, некоторое время назад проверил масштабируемость порождения процессов Erlang к потокам ОС. Он написал простой веб-сервер в Erlang и протестировал его против многопоточного Apache (поскольку Apache использует потоки ОС). Есть старый сайт с данными, датируемыми 1998 годом. Мне удалось найти этот сайт только один раз. Поэтому я не могу предоставить ссылку. Но информация там. Основной момент исследования показал, что Apache максимизировал чуть менее 8K процессов, в то время как его рукописный сервер Erlang обрабатывал 10k+ процессы.