parallel_for中互斥锁的多线程替代方案
Multithreading alternative to mutex in parallel_for
我对C++相当陌生,因此如果这是一个愚蠢的问题,请原谅,但我没有在互联网上找到我正在寻找的好例子。
基本上,我使用parallel_for周期来查找 2D 数组内的最大值(以及介于两者之间的一系列其他操作(。首先,我什至不知道这是否是最好的方法,但考虑到这个 2D 数组的长度,我认为拆分计算会更快。
我的代码:
vector<vector<double>> InterpU(1801, vector<double>(3601, 0));
Concurrency::parallel_for(0, 1801, [&](int i) {
long k = 0; long l = 0;
pair<long, long> Normalized;
double InterpPointsU[4][4];
double jRes;
double iRes = i * 0.1;
double RelativeY, RelativeX;
int p, q;
while (iRes >= (k + 1) * DeltaTheta) k++;
RelativeX = iRes / DeltaTheta - k;
for (long j = 0; j < 3600; j++)
{
jRes = j * 0.1;
while (jRes >= (l + 1) * DeltaPhi) l++;
RelativeY = jRes / DeltaPhi - l;
p = 0;
for (long m = k - 1; m < k + 3; m++)
{
q = 0;
for (long n = l - 1; n < l + 3; n++)
{
Normalized = Normalize(m, n, PointsTheta, PointsPhi);
InterpPointsU[p][q] = U[Normalized.first][Normalized.second];
q++;
}
p++;
}
InterpU[i][j] = bicubicInterpolate(InterpPointsU, RelativeX, RelativeY);
if (InterpU[i][j] > MaxU)
{
SharedDataLock.lock();
MaxU = InterpU[i][j];
SharedDataLock.unlock();
}
}
InterpU[i][3600] = InterpU[i][0];
});
您可以在此处看到,我正在使用名为SharedDataLock
的mutex
来保护访问同一资源的多个线程。MaxU
是一个变量,应仅包含InterpU
向量的最大值。 代码运行良好,但由于我遇到了速度性能问题,我开始研究atomic
和其他一些东西。
有没有关于如何修改类似代码以使其更快的好例子?
正如 VTT 所提到的,您可以简单地找到每个线程的本地最大值,然后合并它们 使用combinable
:
Concurrency::combinable<double> CombinableMaxU;
Concurrency::parallel_for(0, 1801, [&](int i) {
...
CombinableMaxU.local() = std::max(CombinableMaxU.local(), InterpU[i][j]);
}
MaxU = std::max(MaxU, CombinableMaxU.combine(std::max<double>));
请注意,您当前的代码实际上是错误的(除非MaxU
是原子的(,您在锁之外读取MaxU
,而它可以由其他线程同时写入。通常,不得读取同时写入的值,除非双方都受到原子语义或锁和内存围栏的保护。原因是变量访问很可能由多个内存访问组成,具体取决于硬件支持的类型。
但在您的情况下,您甚至有一个经典的争用条件:
MaxU == 1
Thread a | Thread b
InterpU[i][j] = 3 | InterpU[i][j] = 2
if (3 > MaxU) | if (2 > MaxU)
SharedDataLock.lock(); | SharedDataLock.lock();
(gets the lock) | (waiting for lock)
MaxU = 3 | ...
SharedDataLock.unlock(); | ...
... | (gets the lock)
| MaxU = 2
| SharedDataLock.unlock();
MaxU == 2
锁很硬。
您还可以使用原子并计算最大值。但是,我猜1它在循环2中仍然表现不佳,而在循环之外,无论您使用原子还是锁都没有关系。
1:有疑问时,不要猜测 - 测量!
2:仅仅因为某些东西是原子的并且由硬件支持,并不意味着它像访问本地数据一样高效。首先,原子指令通常比非原子指令的成本高得多,其次,您必须处理非常糟糕的缓存效果,因为内核/缓存将争夺数据的所有权。虽然原子在许多情况下可能更优雅(恕我直言,不是这个(,但大多数时候还原速度更快。
- 在C++中使用cURL和多线程
- 多线程双缓冲区
- 为什么我的多线程作业队列崩溃
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 试图创建一个多线程程序来查找0-100000000之间的总素数
- 为什么一个向量上的多线程操作很慢
- 学习多线程C++:添加线程不会使执行速度更快,即使它看起来应该
- 全局变量 多读取器 一个写入器多线程安全?
- boost::文件系统::recursive_directory_iterator多线程安全
- 如何阻止TensorFlow的多线程
- 如何在多线程中正确使用unique_ptr进行多态性?
- 并发/多线程:是否可以以这种方式生成相同的输出?
- sigwait() 在多线程程序中不起作用
- 多线程程序中出现意外的内存泄漏
- 静态 constexpr 类成员变量对多线程读取是否安全?
- 多线程比没有线程C++慢
- parallel_for中互斥锁的多线程替代方案
- 重构多线程方案的单线程 GUI 代码
- 多线程 – 已知的相似性解决方案
- 多线程搜索的解决方案空间很大