我的问题是如何以一种实际上不会降低模拟性能而不是增加模拟性能的方式正确设计以下多线程。
假设您有一个名为MyClass
的类,它包含几个大数组(每个大约500MB)和一个使用这样的数组处理信息的函数:
class MyClass
{
private:
int *data1 = new int[ARRAY_SIZE]();
int *data2 = new int[ARRAY_SIZE]();
public:
void fillData(); //any function that fills the inner data
void processData(const int iteration);
}
模拟的每次迭代都会处理4个MyClass
个实例。在我理想的世界中,我想要做的是将每个这样的实例传递给一个线程,然后在每个线程内部,调用instance.processData()
。使用#include <thread>
,如下所示:
int main()
{
MyClass inst1,inst2, inst3, inst4;
//<----- here you would have code that fills the arrays inside each instance of MyClass
for(int iteration=0; iteration<MAX_ITERATIONS; iteration++)
{
std::thread t1(&MyClass::processData, &inst1, iteration);
std::thread t2(&MyClass::processData, &inst2, iteration);
std::thread t3(&MyClass::processData, &inst3, iteration);
std::thread t4(&MyClass::processData, &inst4, iteration);
t1.join();
t2.join();
t3.join();
t4.join();
}
return 0;
}
我每次迭代都将MyClass
实例分配给线程的原因是,在processData
每个实例结束后,我会在每个实例中对每个实例中的数据结果进行比较迭代
问题在于,所描述的代码实际上比非multhithreded版本慢得多(比较慢的数量级)。那么问题就变成了:我做错了什么?有没有办法改进,考虑到我必须在每次迭代结束时比较每个实例的处理结果?
PS1:我绝对不能对processData
中包含的过程进行并行化。这是100%的问题。
答案 0 :(得分:0)
有几件事可能导致您使用四个线程而不是一个线程来降低性能。以下是要检查的基本内容:
并行化开销:这是创建和同步线程的成本。如果在processData
中完成的工作量很少并且您有大量的迭代,那么线程创建和销毁成本可能是个问题。如果在processData()
中有任何同步结构,例如障碍,锁定或原子操作,这些可能会导致减速。
Thrashing:当单个线程执行时,活动内存集(正在写入和读取的内存)通常比运行多个线程时小得多。这可能导致更多数量的高速缓存未命中(即,由于多个线程必须共享L2和L3高速缓存)。如果您的程序超过了系统上的物理内存量(即交换),则多个线程可能导致页面抖动,而单击线程则不会。
资源争用:如果您的进程正在读取/写入磁盘或网络,您可能正在尝试类似于使用该资源进行颠簸的事情,其中不同的线程阻止彼此有效地访问它。
False Sharing:这是线程在同一缓存行上写入和读取不同位置的地方,反复导致计算被丢弃,因为缓存行无效并刷新。
允许更好诊断的问题:
串行运行时每次迭代执行的总挂钟时间有多长?
使用四个线程时每次迭代执行的总挂钟时间有多长?
什么类型的操作/算法是processData()
(例如,排序,稀疏线性代数,密集线性
这个系统的物理规格是什么(即它有多少物理和逻辑核心,缓存有多大,它有多少物理内存)?
执行了多少次迭代?