你有两个阵列
int[] a = {......} // Total elements 1 million
int[] b = {......} // Total elements 1 million , Length is same for both arrays.
Q1。我必须创建一个数组
int[] c
其元素是[]和b []的相应索引的总和 防爆。
c[0] = a[0] + b[0];
c[1] = a[1] + b[1];
c[2] = a[2] + b[2];
解决方案: - >我可以利用多线程。将整个数组划分为10个或更多部分,并将每个段分配给线程以执行计算。 注意 - >采访者建议使用多线程
Q2。 现在它有点改变。数组C的元素将具有如下值: - >
c[0] = a[0] + b[0];
c[1] = a[1] + b[1] + c[0]; // At this line c[0] is Sum of a[0] + b[0]; The Above Line
c[2] = a[2] + b[2] + c[1]; // At this line c[0] is Sum of a[1] + b[1]+ a[0] + b[0]; The Above Line
MySolution->解决第1部分(Q1)并创建一个临时数组,之后我们必须执行这样的添加。
C[1] = temp[1]+temp[0]
C[2] = temp[2]+temp[1]
注意: - >我们真的不需要temp [],我们只能使用Array c这样做。只是简单地在SO上解释这个。
Problem->我不认为在问题2中我们可以使用多线程。有没有更好的方法来解决Q2?我们可以利用多线程吗?
答案 0 :(得分:5)
在我看来,问题二你有两种技巧:
首先应该分两步完成。 步骤1使用您可以添加的线程
c[0] = a[0] + b[0];
c[1] = a[1] + b[1];
c[2] = a[2] + b[2];
正如你的建议。
但是步骤2应该按顺序完成。因为c[ i + 1]
值取决于c [i]
第二种技术有点复杂但可以很快。
在第二个问题中要求您做的事情是:
c[0] = a[0] + b[0];
c[1] = a[1] + b[1] + a[0] + b[0];
c[2] = a[2] + b[2] + a[1] + b[1] + a[0] + b[0];
这可以是平行的。
c[i] = thread1( sum(a[0]...a[i] )) + thread2( sum(b[0]...b[i] ))
for i >= 0
这项技术很好,您可以为所有c[i]
(它的两个类似级别线程模型)并行计算i
。
你可以进一步改进thread1 / thread2函数作为多线程与子线程来执行求和 - 但是记住有时多线程代码运行速度比单线程代码慢,因为线程上下文切换时间(所以你应该给出足够的任务量)到每个线程)。
与第二种技术不同的一点是" c[i]
的线程的大部分内容与c[i-1]
的线程所做的大致相同"。br />
感谢@ jogojapan让我知道这个缺点。
为了更好的技术阅读,由Mr.Jogojapan更新了answer。
答案 1 :(得分:4)
您可以执行第1部分多线程,如您所说 -
temp[0] = a[0] + b[0];
temp[1] = a[1] + b[1];
temp[2] = a[2] + b[2];
etc....
然后第2部分的计算变为 -
c[0] = temp[0];
c[1] = temp[1] + temp[0];
c[2] = temp[2] + temp[1] + temp[0];
c[3] = temp[3] + temp[2] + temp[1] + temp[0];
etc...
虽然这看起来是连续的并且不可能并行化,但实际上这是一种非常常见的操作,称为“前缀总和”或“扫描”。有关详细信息,包括如何并行化,请参阅Wikipedia或Blelloch。
在8个元素的情况下,每个递归阶段都可以并行化,因为每个计算都不依赖于同一阶段的其他计算。
// 1st phase
u[0] = temp[0] + temp[1];
u[1] = temp[2] + temp[3];
u[2] = temp[4] + temp[5];
u[3] = temp[6] + temp[7];
// 2nd phase
v[0] = u[0] + u[1];
v[1] = u[2] + u[3];
// 3rd phase
w[0] = v[0] + v[1];
// final phase
c[0] = temp[0];
c[1] = u[0];
c[2] = u[0] + temp[2];
c[3] = v[0];
c[4] = v[0] + temp[4];
c[5] = v[0] + u[2];
c[6] = v[0] + u[2] + temp[6];
c[7] = w[0];
答案 2 :(得分:1)
实际上你可以在这个任务中使用多线程。您的算法将包含两部分:
应用Q1算法 - 这部分将利用多线程。
只需在一个循环中应用formyla:c[n] = c[n] + c[n-1]
,n=1...999999
。
答案 3 :(得分:1)
您可以在第1个问题的方式中使用多线程。我的意思是你可以计算
sumA0B0 = a[0] + b[0];
在单独的线程中甚至等待计算(同步,即在[i]上)。然后在单独的线程中,您可以计算c[i] = sumAiBi + c[i-1];
答案 4 :(得分:0)
对Q2使用多线程的一种方法是两次传递(每次使用T线程,其中T可以自由选择):
以通常的多线程方式计算所有单元格的c[i] = a[i] + b[i] + c[i-1]
,即将输入分为[0,r1],[r1,r2],... [rk,n)并将一个线程应用于每个范围。是的,除了第一个范围外,所有范围都不正确,第2步将更正它。
再次以多线程方式计算更正。为此,我们会查找每个范围的最右侧值,即corr1:=c[r1-1]
,corr2:=corr1+c[r2-1]
,corr3:=corr2+c[r3-1]
等,这为我们提供了更正值每个线程,然后再次使用具有与之前相同的范围的多线程计算c[i] += corrk
,其中corrk
是第k个线程的线程特定的校正值。 (对于第0个线程,我们可以使用corr0:=0
,这样线程就不需要做任何事情了。)
这将理论运行时间提高了一个因子T,其中T是线程数(可以自由选择),因此就多线程而言,它是一种最佳解决方案。
为了说明这是如何工作的,这里有一个例子,我们假设长度为n==30
的数组。我们进一步假设我们使用3个线程:一个用于计算范围c[0..9]
,一个用于c[10..19]
,一个用于c[20..29]
。
显然,目标是在单元格c[i]
中,对于任何0<i<n
,我们都会得到
c[i] == a[0]+...+a[i]+b[0]+...+b[i]
算法完成后(即所有a[0..i]
和所有b[0..i]
的总和)。让我们看看算法是如何实现的,例如单元格i==23
。该单元由第三个线程处理,即负责范围c[20..29]
的线程。
第1步:线程集
c[20] = a[20]+b[20]
c[21] = c[20]+a[21]+b[21] == a[20]+a[21]+b[20]+b[21]
c[22] = c[21]+a[22]+b[22] == a[20]+a[21]+a[22]+b[20]+b[21]+b[22]
c[23] = c[22]+a[23]+b[23] == a[20]+a[21]+a[22]+a[23]+b[20]+b[21]+b[22]+b[23]
...
因此,在第1步完成后,我们在单元格a[20..23]
中有一些b[20..23]
和c[23]
。遗漏的是a[0..19]
和b[0..19]
的总和。
同样,第一个和第二个线程已将值设置为c[0..9]
和c[10..19]
,以便
c[0] = a[0]+b[0]
c[1] = c[0]+a[1]+b[1] == a[0]+a[1]+b[0]+b[1]
...
c[9] = a[0]+...+a[9]+b[0]+...+b[9]
和
c[10] = a[10]+b[10]
...
c[19] = a[10]+...+a[19]+b[10]+...+b[19]
步骤2:第三个线程的校正值corr2
是corr1
和第二个线程计算的最右边值的总和,而corr1
是正确的 - 最大值由第一个线程计算。因此
corr2 == c[9]+c[19] == (a[0]+...+a[9]+b[0]+...+b[9]) + (a[10]+...+a[19]+b[10]+...+b[19])
这确实是在步骤1之后c[23]
的值缺失的总和。在步骤2中,我们将此值添加到所有元素c[20..29]
,因此,在步骤2完成后,{{ 1}}是正确的(所有其他单元格也是如此)。
这样做的原因是单元格值的计算是从左到右的严格增量操作,并且计算单个单元格的操作顺序无关紧要(因为{{1}是联想和交换)。因此,在步骤1之后,任何给定线程的最终结果(“最右边的值”)可以用于纠正在第2步中负责其范围的线程的结果。