我想使用n
个线程来计算嵌套循环:
for (i = 0; i < matrix.size(); i++) {
for (j = 0; j < matrix.size(); j++) {
for (k = 0; k < matrix.size(); k++) {
// do the job
}
}
}
我想用不同的线程计算每个循环操作。我们将其称为线程T
。使用3
线程和matrix.size() = 5
,这就是工作分配的方式:
T[0] computes operation i=0 j=0 k=0
T[1] computes operation i=0 j=0 k=1
T[2] computes operation i=0 j=0 k=2
T[0] computes operation i=0 j=0 k=3
T[1] computes operation i=0 j=0 k=4
T[2] computes operation i=0 j=1 k=0
T[0] computes operation i=0 j=1 k=1
T[1] computes operation i=0 j=1 k=2
T[2] computes operation i=0 j=1 k=3
T[0] computes operation i=0 j=1 k=4
T[1] computes operation i=0 j=2 k=0
T[2] computes operation i=0 j=2 k=1
T[0] computes operation i=0 j=2 k=2
T[1] computes operation i=0 j=2 k=3
T[2] computes operation i=0 j=2 k=4
T[0] computes operation i=0 j=3 k=0
T[1] computes operation i=0 j=3 k=1
T[2] computes operation i=0 j=3 k=2
T[0] computes operation i=0 j=3 k=3
T[1] computes operation i=0 j=3 k=4
T[2] computes operation i=0 j=4 k=0
T[0] computes operation i=0 j=4 k=1
T[1] computes operation i=0 j=4 k=2
T[2] computes operation i=0 j=4 k=3
T[0] computes operation i=0 j=4 k=4
T[1] computes operation i=1 j=0 k=0
T[2] computes operation i=1 j=0 k=1
T[0] computes operation i=1 j=0 k=2
T[1] computes operation i=1 j=0 k=3
T[2] computes operation i=1 j=0 k=4
T[0] computes operation i=1 j=1 k=0
T[1] computes operation i=1 j=1 k=1
T[2] computes operation i=1 j=1 k=2
T[0] computes operation i=1 j=1 k=3
T[1] computes operation i=1 j=1 k=4
T[2] computes operation i=1 j=2 k=0
我设法将最后一行更改为:for (k = PROCESSINDEX; k < matrix.size(); k += PROCESSAMOUNT)
,但是结果就是这样分配了工作:
T[0] computed 25 iterations
T[1] computed 50 iterations
T[2] computed 50 iterations
我该如何改善?
答案 0 :(得分:3)
尽管在许多实际任务中(例如,将两个矩阵相乘),将其进一步细分很可能会导致性能下降,因为这会破坏线程的内存局部性,如果您确实执行的任务确实具有较低的数据依赖性,则有一个显而易见的解决方案:您只需枚举从(i,j,k)
到0
的所有三元组n^3-1
(假设n = matrix.size()
),然后将该范围吐出3个几乎相等的块并将它们传递给每个线程。然后,每个线程都可以轻松地将其重构为工作的一部分(任务#t
与i+j*n+k*n^2
相对应,因此:
i = t % n
j = (t/n) % n
k = t / n /n
另一种解决方案是将线程池和队列用于任务。您不必在一开始就为每个线程分配所有工作。您将工作放入队列中,并让每个线程从中获得一些工作量,在处理完该批次后,从队列中取回下一个批次,并使用批次减少队列中的并发冲突。这种方法的优势在于,如果处理数据的时间取决于特定的数据,那么您将平衡实际执行的工作而不是执行的任务数量。