libcppa vs. Erlang vs. Scala в смешанном сценарии

в 8:17, , рубрики: benchmark, c++, erlang, Erlang/OTP, scala

Прим. переводчика: перевод выполнялся для erlanger.ru. Заранее приношу извинения за возможные неточности.

Этот бенчмарк производит следующие действия:

  • симулирует создания и удаления большого количества актеров/процессов
  • отправляет более чем 50 000 000 сообщений между актерами
  • производит сложные численные вычисления для симуляции реальной рабочей нагрузки

Тестовая программа создает 20 колец по 50 актеров в каждом. Токен с начальным значением 10 000 передается по кольцу и его значение уменьшается на единицу при каждой итерации. Клиент, получивший токен, обязательно передает его следующему клиенту в кольце и завершает работу, если значение токена равно 0.

Следующий псевдокод иллюстрирует этот алгоритм:

chain_link(Next):
  receive:
    {token, N} =>
      next ! {token, N}
      if (N > 0) chain_link(Next)

worker(MessageCollector):
  receive:
    {calc, X} =>
      MessageCollector ! {result, prime_factorization(X)}

master(Worker, MessageCollector):
  5 times:
    Next = self
    49 times: Next = spawn(chain_link, Next)
    Next ! {token, 10000}
    Done = false
    while not Done:
      receive:
        {token, X} =>
          if (X > 0): Next ! {token, X-1}
          else: Done = true
  MessageCollector ! {master_done}

Каждое кольцо состоит из 49 chain_link актеров и одного master'а. Мастер перезапускает завершившие работу актеры пять раз. В целом, каждый мастер запускает 245 актеров, а программа запускает 20 master'ов. В общей сложности создается 4921 актер ((20+(20∗245)+1), из которых не более 1021 (20+20+(20∗49)+1) выполняются одновременно. Коллектор сообщений ждет, пока он не получит 100 (20∗5) результатов разложения на простые множители и сообщение о завершении работы от каждого master'а. Вычисление простых множителей используется для симуляции рабочей нагрузки.

Вычисление занимает около двух секунд на тестируемом оборудовании при реализации в виде цикла на C++. Решение с хвостовой рекурсией на Scala работает примерно с такой же скоростью, в то время как решение на Erlang'е выполняет ту же задачу за почти семь секунд.

libcppa vs. Erlang vs. Scala в смешанном сценарии

Как и ожидалось, реализация на Scala, использующая потоки, показывает наихудший результат, хотя увеличение времени работы на восьми и более ядрах нас удивило. Реализация с использованием Akka значительно быстрее, чем обе реализции, использующие стандартные библиотеки.

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

Накладные расходы планировщика libcppa приводят к снижению производительности. Так, накладные расходы на аллокацию стека и переключение контекста потребляют до 10%-20% работы при использовании до 6 ядер CPU, которые являются практически пределом для планировщика.

Бенчмарк показывает, что libcppa является достаточно производительной библиотекой и работает на том же уровне, что существующие реализации actor model, но текущая реализация планировщика не может эффективно использовать более шести ядер.

Бенчмарк запускался на виртуальной машине с Линуксом, которой выделялись от 2 до 12 ядер на хост-системе, состоящей из двух шестиядерных 2.27 Гц процессоров Intel® Xeon®. Все значения являются средними значениями по результатам 5 запусков.

Исходники бенчмарка можно взять на GitHub'е: github.com/Neverlord/cppa-benchmarks.

Автор: dmitriid

Источник

Поделиться

* - обязательные к заполнению поля