Я работал над квантовым моделированием. Каждый временной шаг вычисляется потенциальная функция, один шаг решателя повторяется, и затем проводится серия измерений. Эти три процесса легко распараллеливаются, и я уже убедился, что они не мешают друг другу. Кроме того, есть некоторые вещи, которые довольно просты, но не должны выполняться параллельно. Схема установки показана ниже.
omp_set_num_threads(3);
#pragma omp parallel
{
while (notDone) {
#pragma omp sections
{
#pragma omp section
{
createPotential();
}
#pragma omp section
{
iterateWaveFunction();
}
#pragma omp section
{
takeMeasurements();
}
}
#pragma omp single
{
doSimpleThings();
}
}
}
Код работает просто отлично! Я вижу увеличение скорости, в основном связанное с измерениями, выполняемыми вместе с решателем TDSE (увеличение скорости примерно на 30%). Тем не менее, программа идет от использования около 10% ЦП (около одного потока) до 35% (около трех потоков). Это имело бы смысл, если бы потенциальная функция, итератор TDSE и измерения заняли одинаково много времени, но это не так. Исходя из увеличения скорости, я бы ожидал что-то порядка 15% загрузки процессора.
У меня есть ощущение, что это связано с накладными расходами на запуск этих трех потоков в цикле while. Замена
#pragma omp sections
с
#pragma omp parallel sections
(и пропуская две строки непосредственно перед циклом) ничего не меняет. Есть ли более эффективный способ запустить эту настройку? Я не уверен, что потоки постоянно воссоздаются, или поток удерживает целое ядро, ожидая, пока другие будут выполнены. Если я увеличу количество потоков с 3 до любого другого числа, программа использует столько ресурсов, сколько захочет (это может быть весь ЦП) и не получит прирост производительности.
Я перепробовал много вариантов, включая использование задач вместо секций (с одинаковыми результатами), переключение компиляторов и т. Д. Как и было предложено Qubit, я также пытался использовать std :: async. Это было решение! Загрузка ЦП снизилась примерно с 50% до 30% (это на другом компьютере по сравнению с исходным постом, поэтому цифры отличаются — это увеличение производительности в 1,5 раза при использовании ЦП в 1,6 раза). Это намного ближе к тому, что я ожидал от этого компьютера.
Для справки вот новая схема кода:
void SimulationManager::runParallel(){
auto rV = &SimulationManager::createPotential();
auto rS = &SimulationManager::iterateWaveFunction();
auto rM = &SimulationManager::takeMeasurements();
std::future<int> f1, f2, f3;
while(notDone){
f1 = std::async(rV, this);
f2 = std::async(rS, this);
f3 = std::async(rM, this);
f1.get(); f2.get(); f3.get();
doSimpleThings();
}
}
Три исходные функции вызываются с помощью std :: async, а затем я использую будущие переменные f1, f2 и f3, чтобы собрать все обратно в один поток и избежать проблем с доступом.
Других решений пока нет …