В моей основной функции я установил:
omp_set_num_threads(20);
который говорит OpenMP использовать 20 потоков (иметь 40 доступных потоков).
Затем я выполняю свой код, который содержит директиву:
#pragma omp parallel for shared(x,y,z)
для основного цикла for, и контролировать использование процессора через htop (возможно, не лучшим способом, но все же). Есть 50 «задач», которые должен выполнить цикл for, и каждая занимает довольно много времени. Что я наблюдаю через htop, так это то, что после завершения задач количество потоков уменьшается. В частности, используя 20 потоков, я ожидаю, что ed увидит 2000% использования процессора, пока не осталось менее 20 задач, после которых потоки должны «освободиться». Тем не менее, я вижу первые 2000%, а после того, как n задач выполнено, я вижу 2000% — (n * 100%) производительность. Таким образом, кажется, что когда задачи завершены, потоки закрываются, а не выбирают новые задачи.
Это ожидать или это звучит странно?
Планирование параллельного цикла по умолчанию практически для всех существующих компиляторов OpenMP static
Это означает, что среда выполнения OpenMP будет пытаться равномерно распределить пространство итерации между потоками и выполнять статическое рабочее задание. Поскольку у вас есть 50 итераций и 20 потоков, работа не может быть разделена поровну, так как 20 не делит 50. Следовательно, половина потоков выполнит три итерации, а другая половина сделает две итерации.
Существует неявный барьер в конце parallel
) for
построить, где потоки, которые заканчиваются ранее, ждут завершения остальных потоков. В зависимости от реализации OpenMP, барьер может быть реализован как занятый цикл ожидания, как операция ожидания на каком-либо объекте синхронизации ОС или как комбинация обоих. В последних двух случаях загрузка ЦП потоков, попадающих в барьер, либо сразу падает до нуля, когда они переходят в прерывистый режим сна, либо первоначально остается на уровне 100% в течение короткого времени (цикл занятости), а затем падает до нуля ожидание).
Если итерации цикла занимают одинаковое количество времени, то произойдет то, что загрузка ЦП первоначально будет составлять 2000%, а после двух итераций (и чуть больше, если реализация барьера использует короткий занятый цикл) снизится до 1000 %. Если итерации занимают различное количество времени, то потоки будут приходить в разные моменты к барьеру, и загрузка ЦП будет постепенно уменьшаться.
В любом случае используйте schedule(dynamic)
чтобы каждая итерация была передана первому потоку. Это улучшит загрузку ЦП в случае, когда итерации занимают различное количество времени. Это не поможет, когда итерации занимают одинаковое количество времени каждая. Решение в этом последнем случае будет иметь число итераций как целое число, кратное числу потоков.
Других решений пока нет …