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

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

С Erlang Программирование (2009):

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

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

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

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

мои мысли

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

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

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

чтение

7 ответов


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

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

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

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

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

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

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


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

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

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

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


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

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


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

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


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


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


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