c++

您所在的位置:网站首页 静态调度和动态调度指令的区别 c++

c++

#c++| 来源: 网络整理| 查看: 265

我开始使用 C++ 使用 OpenMP。

我有两个问题:

什么是#pragma omp for schedule ? dynamic有什么区别和 static ? 请举例说明。

最佳答案

其他人已经回答了大部分问题,但我想指出一些特定的情况,其中特定的调度类型比其他的更适合。调度控制如何在线程之间划分循环迭代。选择正确的时间表会对应用程序的速度产生很大的影响。static调度意味着迭代块以循环方式静态映射到执行线程。静态调度的好处在于,OpenMP 运行时保证如果您有两个具有相同迭代次数的独立循环并使用静态调度以相同数量的线程执行它们,那么每个线程将获得完全相同的迭代范围( s) 在两个平行区域。这在 NUMA 系统上非常重要:如果您在第一个循环中接触一些内存,它将驻留在执行线程所在的 NUMA 节点上。然后在第二个循环中,同一个线程可以更快地访问同一个内存位置,因为它将驻留在同一个 NUMA 节点上。

假设有两个 NUMA 节点:节点 0 和节点 1,例如双插槽 Intel Nehalem 板,两个插槽均带有 4 核 CPU。然后线程 0、1、2 和 3 将驻留在节点 0 上,线程 4、5、6 和 7 将驻留在节点 1 上:

| | core 0 | thread 0 | | socket 0 | core 1 | thread 1 | | NUMA node 0 | core 2 | thread 2 | | | core 3 | thread 3 | | | core 4 | thread 4 | | socket 1 | core 5 | thread 5 | | NUMA node 1 | core 6 | thread 6 | | | core 7 | thread 7 | 每个内核都可以从每个 NUMA 节点访问内存,但远程访问比本地节点访问慢(在 Intel 上慢 1.5 到 1.9 倍)。你运行这样的东西:char *a = (char *)malloc(8*4096); #pragma omp parallel for schedule(static,1) num_threads(8) for (int i = 0; i < 8; i++) memset(&a[i*4096], 0, 4096); 如果不使用大页面,在这种情况下,4096 字节是 x86 上 Linux 上一个内存页面的标准大小。此代码将整个 32 KiB 数组清零 a . malloc() call 只是保留虚拟地址空间,但实际上并没有“触及”物理内存(这是默认行为,除非使用其他版本的 malloc,例如,像 calloc() 那样将内存归零)。现在这个数组是连续的,但只在虚拟内存中。在物理内存中,一半位于连接到插槽 0 的内存中,另一半位于连接到插槽 1 的内存中。 这是因为不同的部分被不同的线程归零,并且这些线程驻留在不同的内核上,并且有一种叫做第一次接触的东西NUMA 策略,这意味着内存页分配在第一个“接触”内存页的线程所在的 NUMA 节点上。| | core 0 | thread 0 | a[0] ... a[4095] | socket 0 | core 1 | thread 1 | a[4096] ... a[8191] | NUMA node 0 | core 2 | thread 2 | a[8192] ... a[12287] | | core 3 | thread 3 | a[12288] ... a[16383] | | core 4 | thread 4 | a[16384] ... a[20479] | socket 1 | core 5 | thread 5 | a[20480] ... a[24575] | NUMA node 1 | core 6 | thread 6 | a[24576] ... a[28671] | | core 7 | thread 7 | a[28672] ... a[32768] 现在让我们像这样运行另一个循环:#pragma omp parallel for schedule(static,1) num_threads(8) for (i = 0; i < 8; i++) memset(&a[i*4096], 1, 4096); 每个线程将访问已映射的物理内存,并且它将具有与第一个循环期间相同的线程到内存区域的映射。这意味着线程将只访问位于其本地内存块中的内存,这将是快速的。

现在想象另一个调度方案用于第二个循环:schedule(static,2) .这会将迭代空间“切割”为两个迭代的块,总共会有 4 个这样的块。将会发生的是,我们将有以下线程到内存位置映射(通过迭代次数):

| | core 0 | thread 0 | a[0] ... a[8191]


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3