并行处理数组索引的最佳方法?
Posted
技术标签:
【中文标题】并行处理数组索引的最佳方法?【英文标题】:Optimal way to handle array indexing in parallel? 【发布时间】:2016-09-17 16:34:37 【问题描述】:我有以下情况:我有一个大小为 L 的盒子中的粒子列表,其中 L 是其中一个边的长度。
接下来,我将框拆分为单元格,其中 L/cell_dim = 7。所以有 7*7*7 个单元格。
最后,我阅读了所有的粒子,记下它们的位置,并计算出它们在哪个单元格中。
我在 openMP 并行 for 循环中完成上述操作。但是,我需要以线程安全的方式捕获信息,这样我就不必遍历每个单元格的所有粒子。所以我需要一些方法来将粒子的任意子集并行记录到每个单元中。
我现在的方法利用了 OpenMP 关键代码块。我有一个数组大小 [7][7][7][max_particles],其中 max_particles 是每个单元格的最大粒子数,但远小于粒子总数。我在计数器数组大小[7][7][7]中记录添加的最后一个粒子的索引,并根据我的并行循环中的最新计数更新单元数组:
int cube[7][7][7][10];
int cube_counts[7][7][7]=0;
#pragma omp parallel for num_threads(a lot)
for (int i = 0; i < num_particles; i++)
cell_x = //cell calculation;
cell_y = //ditto;
cell_z = //...;
#pragma omp critical
cube_counts[cell_x][cell_y][cell_z] += 1;
// for readability
int index = cube_counts[cell_x][cell_y][cell_z];
cube[cell_x][cell_y][cell_z][index] = i;
// rest in pseudo code:
foreach cell:
adjacent_cell = cell2
particle_countA = cube_counts[cellx][celly][cellz]
particle_countB = cube_counts[cell2x][cell2y][cell2z]
// these two for loops will cover ~2-4 particles,
// so super small...as a result of the cell analysis above.
for particle in cell:
for particle in cell2:
...do stuff
虽然这可行,但当我能够消除关键块(我在一个具有 60 个物理、240 个逻辑的英特尔协处理器上)时,它的速度提高了 2 倍以上。
如何在不需要关键块的情况下完成此操作?我想过做一个大数组......但是当我遍历 7*7*7*257(其中 257 是粒子数)数组时,我失去了所有我获得的东西。链表仍然有竞争条件。
也许是某种无序的线程安全列表...?
【问题讨论】:
你不能把粒子分成 N 个任意大小大致相等的集合,其中 N 是物理线程的数量吗? @Cheers 和 hth。 - Alf 我不这么认为......也许:粒子本身不是线程安全的——它们与所有其他粒子交互。所以真的,我只需要知道每个细胞中有哪些粒子......以及有多少。我想我可以拆分它们...然后我将拥有 60*7*7*7 链接列表,我必须将它们堆叠在一起成为 7*7*7 链接列表...它可能会变得非常讨厌...和风拥有相似数量的关键操作... 在 open mp 中,关键块是一个非常重的结构,因为它会锁定整个代码片段。锁可能工作得很好。 @Mehno 哇谢谢伙计!!..不知道锁; def 留下这个,因为我认为可能有其他方法可以解决这个问题.. 【参考方案1】:使用锁代替临界区可以进一步驱动:
您可以使用编译器将转换为正确的 x86 特定汇编器指令的原子增量和原子赋值伪调用(“内在函数”)。然而,这取决于平台甚至编译器。
如果您使用现代 c++ 编译器 (C++11),那么 std::atomic_* 可能是最好的方法。
【讨论】:
以上是关于并行处理数组索引的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章
并行执行DynamoDB查询(全局二级索引的BatchGetItems)