Я пишу программу на C++ для моделирования конкретной системы. Для каждого временного интервала большая часть выполнения занимает один цикл. К счастью, это смущает параллель, поэтому я решил использовать Boost Threads для его распараллеливания (я работаю на двухъядерном компьютере). Я ожидаю, что при ускорении будет близка к 2-кратной серийной версии, так как нет блокировки. Однако я нахожу, что ускорения вообще нет.Параллельная версия цикла не быстрее, чем серийная версия
Я реализовал параллельную версию петли следующим образом:
- разбудить две нити (они заблокированы на барьер).
Каждый поток затем выполняет следующие действия:
- Атомарно выборки и приращение глобального счетчика.
- Извлеките частицу с этим индексом.
- Выполните вычисление на этой частице, сохраняя результат в отдельном массиве
- Подождите на работах готового барьере
Основные поток ожидает заданий законченного барьера.
Я использовал этот подход, поскольку он должен обеспечивать хорошую балансировку нагрузки (поскольку каждое вычисление может занимать разные промежутки времени). Мне очень любопытно, что может привести к этому замедлению. Я всегда читал, что атомные переменные бывают быстрыми, но теперь я начинаю задаваться вопросом, имеют ли они свои эксплуатационные издержки.
Если у кого-то есть идеи, что искать или какие-либо намеки, я бы очень признателен. Я пробивал себе голову на неделю, и профилирование не показало много.
EDIT: проблема решена! Я расскажу, как я решил эту проблему. Я снова использовал gprof, но на этот раз скомпилирован без флага оптимизации (-O3). Сразу же профайлер указал, что я проводил невероятное количество времени в функции, которая выполняет вычисления на каждой отдельной частице: намного больше, чем в серийной версии.
Эта функция является виртуальной и доступ к ней осуществляется полиморфно. Я изменил код, чтобы получить доступ к нему напрямую, а не через vtable и voila. Параллельная версия произвела ускорение почти на 2! Такое же изменение в серийной версии мало повлияло.
Я не уверен, почему это так, и было бы интересно, если кто-нибудь знает!
Спасибо всем плакатам. Вы все помогли в некоторой степени, и будет очень сложно принять один ответ.
Интересно, вы пробовали синхронизировать только цикл? Нет ли улучшения вообще или просто неутешительное улучшение? Вы проверили в диспетчере задач, что ваше приложение фактически создает два потока? Может быть, ваша память приложений интенсивна, возможно, у вас есть узкое место в памяти? Вы также можете попытаться просто разделить массив и позволить каждому потоку обрабатывать одну половину, просто чтобы увидеть, будет ли какая-либо разница. – Ivan
Да, я приурочен и профилировал только цикл и ничего больше. Существует неутешительное улучшение: ускорение варьируется от 0,9 до 1,1. Диспетчер задач показывает, что оба процессора очень заняты. Нити не выделяют никакой новой памяти. Единственная запись в один массив, и они пишут в независимых местах, и они никогда не читают из того же массива. Когда я разбил массив на два, я получил аналогичную производительность. –