Я рекомендую вам просмотреть слайды Скотта Мейера Кэши ЦП и почему вы заботитесь . Особый интерес для вас представляет слайд 8, на котором показано, как наивному подходу добавления многопоточности к алгоритму на самом деле требуется 16 физических потоков ЦП, чтобы соответствовать производительности одного потока , а 2 потока примерно вдвое медленнее , чем один поток (очень похоже на ваш эксперимент). Херб Саттер также имеет множество статей и семинаров, посвященных этой теме, и Поваренная книга по оптимизации программного обеспечения - превосходная книга по этой теме. И, конечно же, есть Искусство многопроцессорного программирования . Обратите внимание, что Ничего Я упоминал выше, что-то связано с Ruby. Это не случайно, тема / проблема является фундаментальной и происходит от оборудования .
В результате получается, что даже если ваши мьютексы легковесны и реализованы только в пространстве пользователя (без поездки в землю ядра), вы работаете с алгоритмом когерентности кэша ЦП . Каждый раз, когда вы обнаруживаете, что просматриваете код, который в параллельной среде изменяет общее состояние примерно так же часто, как и его чтение (подсказка: ваша защита стека Mutex равна точно такого общего состояния, а также самого стека) вы должны ожидать довольно ужасную производительность, гораздо медленнее, чем один поток. В основном все ваши обращения к такому общему состоянию должны обслуживаться из основного ОЗУ, а не из кеша, а это примерно в 100 раз медленнее. Один поток заплатит этот штраф только при первом доступе, все последующие доступы будут из кэша L1 / L2.
Вот почему серьезное многопоточное приложение
- не делить состояние между потоками
- использовать конструкции без блокировки
Искусство того, как этого добиться, варьируется от случая к случаю (я настоятельно рекомендую книги, ссылки на которые были раньше) Трюки включают получение работы большими партиями вместо одного элемента за раз (таким образом, конфликт возникает гораздо реже и амортизируется по многим элементам), разделение общего состояния (стека) для уменьшения конкуренции, использование стека без блокировки (не тривиальная задача для реализации).