Thread-ring benchmark

Today I was doing the thread ring exercise from the Programming Erlang book and googled for other solutions to compare. I found that the language shootout has exactly the same problem as a benchmark. I had the impression that this is an area where Erlang should be fast, but turns out that C and C++ are again on top. My suspicion is that the C/C++ programs are not following the rules which say "pass the token from thread to thread". It seems, after reading them, that they both manipulate some shared memory and global variables which is different from the Erlang code but I could be wrong.

My question is: are they doing the same thing or the C/C++ code is conceptually different (and faster) from the Erlang one?

And another question: why is Haskell faster than Erlang when the solutions are very similar?

9
задан Daniel Velkov 4 October 2014 в 19:46
поделиться

7 ответов

В конечном счете, передача сообщений на современных машинах реализуется с использованием некоторой формы разделяемой памяти для передачи сообщений (вместе с блокировками или атомарными инструкциями). Таким образом, все реализации C и C ++ на самом деле встраивают реализацию передачи сообщений прямо в свой код. Аналогичный тест, использующий библиотеку быстрой передачи сообщений на C, также протестированный на Haskell и Erlang, можно найти в этой статье: http://www.cs.kent.ac.uk/pubs/2009/2928 /index.html (раздел 5.1)

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

6
ответ дан 4 December 2019 в 07:13
поделиться

почему Haskell быстрее Erlang, когда решения очень похожи?

Haskell GHC - это скомпилированная, оптимизированная для нативного кода языковая реализация с очень быстрыми потоками. Обычно это намного быстрее, чем Erlang / HIPE. Erlang не имеет монополии на легкие потоки: -)

4
ответ дан 4 December 2019 в 07:13
поделиться

Версия C использует LWP, который, как мне кажется, является библиотекой потоковой передачи пользовательского пространства. Насколько это «несправедливо», остается предметом споров: я бы посмотрел на такие вещи, как, например, поддерживает ли он настоящий упреждающий параллелизм в том смысле, что вы можете выполнять блокирующие системные вызовы в потоке, не блокируя все другие потоки (вы можете сделать это в Haskell, можно ли в Erlang?).

Потоки Haskell немного легче, чем потоки Erlang, потому что, насколько я понимаю, поток Erlang имеет локальную кучу (в стандартной реализации), тогда как все потоки Haskell используют одну и ту же кучу.

9
ответ дан 4 December 2019 в 07:13
поделиться

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

Все сводится к следующему: В Erlang нет потоков, как таковых - в нем есть процессы с асинхронными коммуникациями. Процессы (намеренно) изолированы друг от друга в значительной степени. С одной стороны, это значительно облегчает разработку - в частности, один процесс может влиять на другой только через определенные, четко обозначенные каналы связи. Под капотом он использует множество трюков (почти наверняка включая разделяемую память) для оптимизации процессов и использования преимуществ, возможных в конкретной реализации/ситуации (например, все процессы работают в едином, разделяемом адресном пространстве). Тем не менее, необходимость скрывать все уловки не позволяет ему быть столь же эффективным, как, например, версия на C, где все "уловки" явные и полностью открыты.

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

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

5
ответ дан 4 December 2019 в 07:13
поделиться

Я бы ответил другим вопросом: как среда выполнения Erlang реализована под капотом?

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

Теперь, почему вы находите это таким странным, что оптимизированная версия C (в перестрелке, конечно, не показывает код среднего уровня) превзошла бы Версия Erlang, учитывая, что Erlang добавляет свой собственный уровень сложности / косвенности?

Независимо от типа теста, реализация C всегда может превзойти наиболее совершенную программу на другом языке ... построенная на C, просто потому что вы берете C-версию, которую она генерирует, а затем удаляет ненужные биты.

С другой стороны:

  • сколько времени вам потребовалось, чтобы написать свой код?
  • какова ваша степень уверенности в том, что он делает правильные вещи? не будет тупиковой?
  • какой из них вы бы предпочли сохранить?

Иногда «быстрее» просто не стоит затрат.

4
ответ дан 4 December 2019 в 07:13
поделиться

не следуя правилам

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

Теперь посмотрите на производительность тех же программ, измеренную с различными конфигурациями времени выполнения, и обратите внимание, насколько это важно -

SMP quad core 
1.0 C GNU gcc #3    4.16    4.17    16,952  607   100% 0% 1% 0%
4.2 Haskell GHC     17.99   17.42   4,020   307   100% 1% 1% 1%
7.5 Erlang HiPE     31.12   31.13   10,504  273   0% 0% 0% 100%

No SMP one core
1.0 C GNU gcc #3    4.16    4.16    16,952  607   1% 0% 0% 100%
1.4 Haskell GHC     5.89    5.89    3,204   307   0% 0% 0% 100%
2.6 Erlang HiPE     10.64   10.63   9,276   273   0% 0% 0% 100%
2
ответ дан 4 December 2019 в 07:13
поделиться

Одна вещь, которую следует отметить в этом тесте, заключается в том, что можно передать только один токен. Это означает, что на практике это просто однопоточная программа, читающая и записывающая из/в память.

Я ожидаю, что результат будет другим на многопроцессорной машине (или сделать ее кластерной), где потоки/процессы должны передавать M токенов в произвольном порядке.

Хм. Также дайте разработчикам эталонных решений равное количество часов для завершения их решения. Тогда я бы ожидал, что Erlang выйдет на первое место (или, по крайней мере, близко к вершине).

1
ответ дан 4 December 2019 в 07:13
поделиться