Посмотрим, насколько всё плохо в Ruby с параллелизмом: юзабельны ли треды? Возможно ли вообще в Ruby параллельное программирование? Опыты проведём на огромном компьютере Fujitsu-Siemens PRIMEPOWER 850 с установленным Sun Solaris 9.
Будем одновременно считать суммы первых N членов разложения нескольких S сходящихся числовых рядов, затем эти суммы сложим.
Естественно, такая задача запросто решается при помощи парадигмы MapReduce. Для работы у нас есть восемь процессоров SPARC64 по тысяче мегагерц каждый и тридцать два гигабайта оперативной памяти на всю систему.
Физического, математического или глубинного смысла здесь искать не стоит: надо просто чем-то нагрузить вычислитель, чтобы время на выделение нового процесса или треда было пренебрежимо мало по сранению со временем решения задачи в этом процессе или треде.
Сравним производительность работы в трёх случаях:
- параллелизм на основе процессов;
- параллелизм на основе тредов;
- последовательное выполнение программы.
Для этого дела я написал достаточно простой бенчмарк: parallel-bench.rb.
Вместо того, чтобы обсуждать код, лучше поговорить сразу о результатах измерений. Для пущей наглядности я представил их в виде гистограммы. Чем короче столбик, тем лучше результат.

Легко сделать выводы.
- Реализация Thread в MRI 1.8.7 и 1.9.2 сделана через GIL и на самом деле все Ruby-треды выполняются последовательно на одном процессоре, с огромным оверхедом. Треды в Ruby не просто неэффективны, они ужасно вредны.
- При использовании процессов, параметр CPU влияет на число воркеров, выделяемых на задачу, отчего производительность повышается примерно в CPU раз. В целом, вариант на процессах гораздо шустрее.
- Почему при
CPU=1вариант с процессами оказался самым медленным? Дело в том, что после каждого этапа вычислений, создаётся новый процесс вычисления следующего члена числового ряда и убивается отработавший. Куча дополнительного времени тратися впустую.
Итак, старый суперкомпьютер подтвердил очевидную вещь: преимущества параллельного программирования заметны лишь в том случае, когда время решения каждого этапа исходной задачи несопоставимо больше, чем временные затраты на обеспечение параллелизма. Когда такое условие выполняется, игра чертовски стоит свеч!
К сожалению, выбросить GIL из MRI не представляется возможным. Сегодня все мечты о «настоящем параллелизме» возлагаются на JRuby, а завтра — на Rubinius.