我想读取一个输入文件(在 C/C++ 中)并尽可能快地独立处理每一行。处理本身需要一些滴答声,所以我决定使用 OpenMP 线程。我有这个代码:
#pragma omp parallel num_threads(num_threads)
{
string line;
while (true) {
#pragma omp critical(input)
{
getline(f, line);
}
if (f.eof())
break;
process_line(line);
}
}
我的问题是,如何确定要使用的最佳线程数?理想情况下,我希望在运行时动态检测到这一点。我不了解 DYNAMIC 计划选项parallel
,所以我不能说这是否有帮助。有什么见解吗?
另外,我不确定如何“手动”确定最佳数量。我为我的特定应用尝试了各种数字。我原以为报告的 CPU 使用率top
会有所帮助,但它没有(!)在我的情况下,CPU 使用率始终保持在 num_threads*(85-95) 左右。但是,pv
为了观察我读取输入的速度,我注意到最佳数字在 2-5 左右;高于此,输入速度变小。所以我的问题是 - 为什么在使用 10 个线程时我会看到 850 的 CPU 使用率?这可能是由于 OpenMP 如何处理等待进入临界区的线程效率低下吗?
编辑:这里有一些时间。我通过以下方式获得了它们:
for NCPU in $(seq 1 20) ; do echo "NCPU=$NCPU" ; { pv -f -a my_input.gz | pigz -d -p 20 | { { sleep 60 ; PID=$(ps gx -o pid,comm | grep my_prog | sed "s/^ *//" | cut -d " " -f 1) ; USAGE=$(ps h -o "%cpu" $PID) ; kill -9 $PID ; sleep 1 ; echo "usage: $USAGE" >&2 ; } & cat ; } | ./my_prog -N $NCPU >/dev/null 2>/dev/null ; sleep 2 ; } 2>&1 | grep -v Killed ; done
NCPU=1 [8.27MB/s] 使用率:98.4
NCPU=2 [12.5MB/s] 使用率:196
NCPU=3 [18.4MB/s] 使用:294
NCPU=4 [23.6MB/s] 使用率:393
NCPU=5 [28.9MB/s] 使用:491
NCPU=6 [33.7MB/s] 使用:589
NCPU=7 [37.4MB/s] 使用率:688
NCPU=8 [40.3MB/s] 使用率:785
NCPU=9 [41.9MB/s] 使用:884
NCPU=10 [41.3MB/s] 使用率:979
NCPU=11 [41.5MB/s] 使用率:1077
NCPU=12 [42.5MB/s] 使用率:1176
NCPU=13 [41.6MB/s] 使用率:1272
NCPU=14 [42.6MB/s] 使用率:1370
NCPU=15 [41.8MB/s] 使用:1493
NCPU=16 [40.7MB/s] 使用:1593
NCPU=17 [40.8MB/s] 使用率:1662
NCPU=18 [39.3MB/s] 使用率:1763
NCPU=19 [38.9MB/s] 使用率:1857
NCPU=20 [37.7MB/s] 使用:1957
我的问题是我可以在 785 CPU 使用率下实现 40MB/s,但也可以在 1662 CPU 使用率下实现。那些额外的周期去哪里了?
EDIT2:感谢 Lirik 和 John Dibling,我现在明白了,我发现上面的时序令人费解的原因与 I/O 无关,而是与 OpenMP 实现关键部分的方式有关。我的直觉是,如果您在 CS 中有 1 个线程和 10 个线程等待进入,那么在第一个线程退出 CS 的那一刻,内核应该唤醒另一个线程并让它进入。时序表明并非如此:它可以线程会自行唤醒多次并发现 CS 被占用?这是线程库还是内核的问题?