- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我想读取一个输入文件(在 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);
}
}
我的问题是,如何确定要使用的最佳线程数?理想情况下,我希望在运行时动态检测到它。我不明白 parallel
的 DYNAMIC schedule 选项,所以我不能说这是否有帮助。有什么见解吗?
此外,我不确定如何“手动”确定最佳数量。我为我的特定应用程序尝试了各种数字。我原以为 top
报告的 CPU 使用率会有帮助,但它没有(!)在我的例子中,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
中央处理器=1[8.27MB/秒]使用率:98.4
中央处理器=2[12.5MB/秒]用法:196
中央处理器=3[18.4MB/秒]用法:294
中央处理器=4[23.6MB/秒]用法:393
中央处理器=5[28.9MB/秒]用法:491
中央处理器=6[33.7MB/秒]用法:589
中央处理器=7[37.4MB/秒]用法:688
中央处理器=8[40.3MB/秒]用法:785
中央处理器=9[41.9MB/秒]用法:884
中央处理器=10[41.3MB/秒]用法:979
中央处理器=11[41.5MB/秒]用法:1077
中央处理器=12[42.5MB/秒]用法:1176
中央处理器=13[41.6MB/秒]用法:1272
中央处理器=14[42.6MB/秒]用法:1370
中央处理器=15[41.8MB/秒]用法:1493
中央处理器=16[40.7MB/秒]用法:1593
中央处理器=17[40.8MB/秒]用法:1662
中央处理器=18[39.3MB/秒]用法:1763
中央处理器=19[38.9MB/秒]用法:1857
中央处理器=20[37.7MB/秒]用法:1957
我的问题是我可以在 785 CPU 使用率和 1662 CPU 使用率下达到 40MB/s。那些额外的周期去哪儿了??
EDIT2:感谢 Lirik 和 John Dibling,我现在明白我发现上面令人费解的时序的原因与 I/O 无关,而是与 OpenMP 实现关键部分的方式有关。我的直觉是,如果 CS 中有 1 个线程,并且有 10 个线程等待进入,当第一个线程退出 CS 时,内核应该唤醒另一个线程并让它进入。 timings 另有建议:线程是否会自行唤醒多次并发现 CS 已被占用?这是线程库或内核的问题吗?
最佳答案
"I want to read an input file (in C/C++) and process each line independently as fast as possible."
从文件中读取会使您的应用程序 I/O 受限,因此仅读取部分您能够实现的最大性能是以最大磁盘速度读取(在我的机器上,CPU 时间不到 10%)。这意味着,如果您能够完全从任何处理中释放读取线程,则需要处理时间少于剩余的 CPU 时间(我的计算机为 90%)。如果线路处理线程占用的时间超过了剩余的CPU时间,那么你就跟不上硬盘了。
在这种情况下有几种选择:
"...the processing takes a few ticks itself, so I decided to use OpenMP threads"
这是一个好兆头,但也意味着您的 CPU 使用率不会很高。这是您可以优化性能的部分,最好手动完成,正如 John Dibling 提到的那样。通常,最好将每一行都排入队列,让处理线程从队列中拉取处理请求,直到您没有其他要处理的内容为止。后者也称为生产者/消费者设计模式 - 并发计算中非常常见的模式。
Why is there be a difference between
- (i) each process get lock, pull data, release lock, process data; and
- (ii) one process: pull data, get lock, enqueue chunk, release lock,
- others: get lock, dequeue chunk, release lock, process data?
区别很小:在某种程度上,两者都代表消费者/生产者模式。在第一种情况 (i) 中,您没有实际的队列,但您可以将文件流视为您的生产者(队列),而消费者是从流中读取的线程。在第二种情况 (ii) 中,您显式地实现了消费者/生产者模式,该模式更健壮、可重用并为生产者提供了更好的抽象。如果您决定使用多个“输入 channel ”,那么后一种情况更好。
最后(可能也是最重要的),您可以使用 lock-free queue使用单个生产者和单个消费者,这将使 (ii) 在让您受到 i/o 约束方面比 (i) 快得多。使用无锁队列,您可以拉取数据、入队和dequque block 无需锁定。
关于c++ - OpenMP 如何实现对临界区的访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10922558/
OpenMP 中的高斯消除。我是 openmp 的新手,想知道我是否在正确的地方使用了我的编译指示和屏障。我的 x 值每次都不同。他们应该是一样的吗?? #include int num; doub
给定一个示例函数(示例在下面给出),for 循环可以使用 OpenMP 并行化或使用矢量化进行矢量化(假设编译器执行矢量化)。 示例 void function(float* a, float* b,
OpenMP 中原子和关键之间有什么区别? 我能做到 #pragma omp atomic g_qCount++; 但这和不一样吗 #pragma omp critical g_qCount++; ?
我有一个关于如何在您考虑特定依赖关系图时生成 OpenMP 伪代码的问题。 所以假设我们有这个特定的图表: 解决方案可能是这样的: #pragma omp parallel {
我正在尝试使用 openmp 计算二维矩阵的平均值。这个二维矩阵实际上是一个图像。 我正在对数据进行线程分割。例如,如果我有 N线程比我处理行/N thread0 的行数, 等等。 我的问题是:我可以
我想统计测量与 OpenMP 并行化的程序的性能。我选择在执行并行算法的测试应用程序中编写循环 MAX_EXPERIMENTS次并将时间测量报告到文件中。 问题解决方案似乎比提取外部循环上方的并行编译
我找到了 Intel's performance suggestion on Xeon Phi关于 OpenMP 中的 Collapse 子句。 #pragma omp parallel for co
如何使用 OpenMP 并行化数组移位? 我尝试了一些方法,但在以下示例中没有得到任何准确的结果(该示例旋转 Carteira 对象数组的元素,用于排列算法): void rotaciona(int
我有一系列对几个独立函数的调用。 func1(arg); func2(arg); func3(arg); 我想并行执行它们,而不是串行执行它们。我目前正在使用 #pragma omp parallel
我正在尝试使用 openmp 任务来安排基本 jacobi2d 计算的平铺执行。在 jacobi2d 中,依赖于 A(i,j) 从 A(i, j) A(i-1, j) A(i+1, j) A(i, j
我在 3 天前开始使用 OpenMP。我想知道如何使用#pragma使每个内核运行一个线程。详细信息:- int ncores = omp_get_num_procs();for(i = 0; i <
我有一段代码(它是应用程序的一部分),我正在尝试使用 OpenMP 对其进行优化,正在尝试各种调度策略。就我而言,我注意到 schedule(RUNTIME)条款比其他条款有优势(我没有指定 chun
我有一个数字运算 C/C++ 应用程序。它基本上是不同数据集的主循环。我们可以使用 openmp 和 mpi 访问一个 100 节点的集群。我想加速应用程序,但我是 mpi 和 openmp 的绝对新
在 OpenMP 中使用ompsections时,线程会被分配到sections内的 block ,还是每个线程会被分配到每个section? 当nthreads == 3时: #pragma omp
我正在尝试在 cython 中使用 openmp。我需要在 cython 中做两件事: i) 在我的 cython 代码中使用 #pragma omp single{} 作用域。 ii) 使用#pra
我正在尝试通过将循环的每次迭代作为 OpenMP 部分来并行化 OpenMP 中基于范围的 for 循环。我想这样做: #pragma omp parallel sections { for ( au
我正在尝试在 cython 中使用 openmp。我需要在 cython 中做两件事: i) 在我的 cython 代码中使用 #pragma omp single{} 作用域。 ii) 使用#pra
我想编写一个代码转换器,它采用基于 OpenMP 的并行程序并在集群上运行它。 我该如何解决这个问题?我使用哪些库?如何为此设置小型集群? 我发现很难在 Internet 上找到有关集群计算的好 Ma
我是 OpenMP 的新手。我正在尝试为 for 循环使用多个内核,但出现此编译错误: “错误 C3016:'x':OpenMP 'for' 语句中的索引变量必须具有带符号的整数类型”。 我知道 Op
如果我使用 VS 2010 编译器从 Qt Creator 构建项目,我如何启用 OpenMP(从 Visual Studio 构建时,您只需启用该功能)谢谢 最佳答案 在 .pro 文件中尝试下一步
我是一名优秀的程序员,十分优秀!