C# / C++中的同步并行处理

10

我有一个包含数据的数组x[]。还有一个“系统状态”的数组c[]。流程如下:

for(i = 1; i < N; i++)
{   
  a = f1(x[i] + c[i-1]);
  b = f2(x[i] + c[i-1]);
  c[i] = a + b;
}

在双核系统中使用两个并行线程查找f1f2的值是否有有效的方法?我的意思是以下伪代码:

thread_1
{
    for(i = 1; i < N; i++)
      a = f1(x[i] + c[i-1]);    
}
thread_2
{
    for(i = 1; i < N; i++)
    {
      b = f2(x[i] + c[i-1]);
      c[i] = a + b;  //here we somehow get a{i} from thread_1
    }
}

f1f2不花费太多时间,但需要计算很多次,所以期望的加速比为x2。请参阅以下图表以获得图形表示:

desired parallel process

寻找适用于Windows的代码示例。


1
只��当f1和f2非常繁重且同步开销小于并行运行的利润时,才会变得高效。 - gabba
为什么这被标记为C# C++?你使用的是哪种语言? - Lucas Trzesniewski
选择编程语言取决于哪种语言可以更有效地解决任务。 - carimus
3个回答

4
如果我理解正确,a [i]只有在c [i-1]可用时才能计算,b [i]只有在c [i-1]可用时才能计算,c [i]只有在计算a [i]b [i]后才可用。这意味着您唯一可以分别执行的过程是计算a [i]b [i]。以下是我在C#中的理解:
for (int i = 1; i < N; i++)
{
    Task<double> calcA = Task.Factory.StartNew(() => { return f1(x[i] + c[i-1]); });
    Task<double> calcB = Task.Factory.StartNew(() => { return f2(x[i] + c[i-1]); });

    // .Result will block the execution and wait for both calculations to complete
    c[i] = calcA.Result + calcB.Result; 
}

这将运行两个单独的线程,它们分别计算f1f2。在f1f2都计算完之后,它将设置c[i]的值,并运行下一次迭代。 请注意:
  • 我使用double,假设您的f1f2返回double
  • 循环从1开始,假设您有一些初始的a[0]b[0]值。否则,c[i-1]将会抛出异常
  • 只有在与其他计算相比,计算f1f2需要消耗大量资源且时间较长时,此方法才会显示出改进。
  • Task.Factory.StartNew(与使用Thread不同)使用线程池,这意味着它不会每次都创建一个新的线程,而是重复利用线程池中已经存在的线程。 这显著降低了开销。

1
只有当f1和f2非常繁重且同步开销小于并行运行的利润时,才会变得高效。 - gabba
1
我认为WaitAll不是必要的,因为Result会等待任务完成它的工作。 - Hamid Pourjam
你在每次迭代时都打开新线程,这种解决方案很直接。但是否有办法让线程一直运行并与内存进行同步呢? - carimus
@carimus 我可以想象一些情况,但我相信这不会带来任何改进。Task.Factory使用ThreadPool,这意味着它不会每次创建一个新线程 - 它会重用池中现有的线程。 - Yeldar Kurmangaliyev
1
"Parallel.Invoke"会更高效。 - Lucas Trzesniewski
显示剩余3条评论

4

这个算法中唯一需要并行处理的是f1和f2的计算,但你说这两个计算不会消耗太多时间,因此最好使用SIMD向量化技术(例如C#中的System.Numerics.Vectors)在一个核心上运行,这样还能减少缓存未命中的情况。或者也许你可以修改算法以实现并行化(但可能需要付出很大努力)。


2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接