Boost.Thread нет ускорения? - PullRequest
2 голосов
/ 20 мая 2011

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

int bankroll = 50000;
int hands = 100;
int tests = 10000;
Simulation::strategy = hi_lo;

for(int i = 0; i < simulations; ++i)
   runSimulation(bankroll, hands, tests, strategy);

Вся программа, запущенная в одном потоке на моей машине, занимает около 10 секунд.

Я хотел бы использовать 3 ядра, которые есть в моем процессорепоэтому я решил переписать программу, чтобы просто выполнить различные стратегии в отдельных потоках, как это:

int bankroll = 50000;
int hands = 100;
int tests = 10000;
Simulation::strategy = hi_lo;
boost::thread threads[simulations];

for(int i = 0; i < simulations; ++i)
   threads[i] = boost::thread(boost::bind(runSimulation, bankroll, hands, tests, strategy));

for(int i = 0; i < simulations; ++i)
   threads[i].join();

Однако, когда я запустил эту программу, хотя я получил те же результаты, это заняло около 24 секунд, чтобы завершить,Я что-то здесь упустил?

Ответы [ 5 ]

5 голосов
/ 20 мая 2011

Если значение simulations велико, вы в конечном итоге создаете много потоков, а накладные расходы могут привести к разрушению любого возможного прироста производительности.

РЕДАКТИРОВАТЬ : Один из подходов к этому может состоять в том, чтобы просто запустить три потока и позволить каждому из них запустить 1/3 требуемого моделирования. Кроме того, может помочь использование пула потоков какого-либо рода.

2 голосов
/ 20 мая 2011

Это хороший кандидат для рабочей очереди с пулом потоков. Я использовал Intel Threading Blocks (TBB) для таких требований. Используйте пулы ручной работы для быстрого взлома тоже. В Windows ОС предоставляет вам хорошую рабочую очередь с поддержкой пула потоков "QueueUserWorkItem ()"

1 голос
/ 20 мая 2011

Прочитайте эти статьи от Херба Саттера. Вы, вероятно, жертва "ложного обмена".

http://drdobbs.com/go-parallel/article/showArticle.jhtml?articleID=214100002

http://drdobbs.com/go-parallel/article/showArticle.jhtml?articleID=217500206

0 голосов
/ 13 августа 2012

Я опоздал на эту вечеринку, но хотел отметить две вещи для других, кто сталкивался с этим постом:

1) Определенно посмотрите вторую ссылку Херба Саттера, на которую указывает Дэвид (http://www.drdobbs.com/parallel/eliminate-false-sharing/217500206). Это решило проблему, которая привела меня к этому вопросу, обрисовав в общих чертах обертку объекта данных структуры, которая гарантирует, что отдельные параллельные потоки не конкурируют за ресурсы со штаб-квартирой на одна и та же строка кэша памяти (аппаратные элементы управления не позволят нескольким потокам одновременно обращаться к одной и той же строке кэша памяти).

2) По первоначальному вопросу, dlev указывает на большую часть проблемы, но, поскольку я уверен, что это симуляция, есть более глубокая проблема, которая замедляет процесс. Хотя ни одна из высокоуровневых переменных вашей программы не является общей, у вас, вероятно, есть одна критическая системная переменная, которая является общей: системное «последнее случайное число», которое хранится в тайнике и используется для создания следующего случайного числа. Возможно, вы даже инициализируете выделенные объекты-генераторы для каждой симуляции, но если они вызывают такие функции, как rand (), то они, и, расширяя свои потоки, делают повторные вызовы одного и того же общего системного ресурса и впоследствии блокируют друг друга. ,

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

0 голосов
/ 20 мая 2011

Я согласен с dlev. Если ваша функция runSimulation не меняет ничего, что потребуется для правильной работы следующего вызова «runSimulation», вы можете сделать что-то вроде:

, Разделите «симуляции» на 3.

, Теперь у вас будет 3 счетчика «0 для симуляции / 3» »(симуляция / 3 + 1) к 2 симуляции / 3» и «(2 * симуляция) / 3 + 1 для симуляции».

Все эти 3 счетчика могут использоваться одновременно в трех разных потоках.

** ПРИМЕЧАНИЕ :: ** Ваше требование может вообще не подходить для такого типа проверки в случае, если вам нужно сделать общую блокировку данных и все

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...