在我的主函数中,我设置了:
omp_set_num_threads(20);
其告诉OpenMP使用20个线程(具有40个可用线程)。
然后我执行包含指令的代码:
#pragma omp parallel for shared(x,y,z)
对于main for循环,并通过htop监控CPU使用情况(可能不是最好的方法,但仍然如此)。for循环必须执行50个"任务",每个任务都需要相当长的时间。我通过htop观察到,在任务完成后,线程数会下降。具体来说,使用20个线程,我预计ed会看到2000%的cpu使用率,直到剩余的任务少于20个,之后线程应该"释放"自己。然而,我看到的是最初的2000%,在n个任务完成后,我看到2000%-(n*100%)的性能。因此,当任务完成时,线程似乎关闭了,而不是开始执行新任务。
这是意料之中的事,还是听起来很奇怪?
几乎所有现有OpenMP编译器的默认并行循环调度是static
,这意味着OpenMP运行时将尝试在线程之间平均分配迭代空间,并进行静态工作分配。由于您有50次迭代和20个线程,因此工作不能平分,因为20不等于50。因此,一半的线程将进行三次迭代,而另一半将进行两次迭代。
在(组合的parallel
)for
构造的末尾有一个隐式屏障,在此屏障中较早完成的线程等待其余线程完成。根据OpenMP实现的不同,屏障可能被实现为繁忙等待循环,或者被实现为某个操作系统同步对象上的等待操作,或者两者的组合。在后两种情况下,遇到障碍的线程的CPU使用率要么在进入可中断睡眠时立即降至零,要么最初在短时间内保持100%(繁忙循环),然后降至零(等待)。
如果循环迭代花费的时间完全相同,那么CPU使用率最初将为2000%,然后在两次迭代后(如果屏障实现使用短繁忙循环,则会多一点)将降至1000%。如果每次迭代花费的时间不同,那么线程将在不同的时刻到达屏障,CPU使用率将逐渐降低。
在任何情况下,使用schedule(dynamic)
将每个迭代都提供给第一个线程以使其可用。这将在迭代花费不同时间的情况下提高CPU利用率。当迭代每次花费相同的时间时,这将没有帮助。后一种情况下的解决方案是将迭代次数设为线程数的整数倍。