C# / C++ 中的同步并行进程

Synchronous Parallel Process in C# / C++

我有一个包含数据的数组 x[]。还有一个"system states"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;
}

有没有什么有效的方法可以在使用 2 个并行线程的 2 核系统上找到 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。图形表示见图表:

正在寻找 Windows 的代码示例。

如果我没理解错的话,

  • 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; 
}

这将 运行 两个单独的线程,它们将分别计算 f1f2f1f2都计算完后,会设置c[i]值,下一次迭代运行。

注意:

  • 我用double,假设你的f1f2returndouble
  • 循环从 1 开始,假设您有一些初始值 a[0]b[0]。否则,c[i-1] 会抛出异常
  • 与其他计算
  • 相比,如果 f1f2 的计算确实耗费资源且耗时长,这只会带来改进
  • Task.Factory.StartNew(与使用 Thread 不同)使用线程池,这意味着它不会每次都创建一个新线程,而是重用池中的现有线程。它显着减少了开销。

在不进入代码解决方案的情况下,您想使用某种障碍。这允许检查是否所有参与者都已声明他们已完成任务。在此示例中,线程 2 必须等待线程 1

https://en.wikipedia.org/wiki/Barrier_(computer_science) Example of C++ "Memory barrier"

这个算法中唯一的并行部分是f1和f2的计算,但是你说f1和f2不耗时,所以使用SIMD向量化可能会好得多(例如C#中的System.Numerics.Vectors ) 和 运行 它在一个核心上(这也减少了缓存未命中)。或者您可以修改您的算法以使其可并行化(但这可能需要艰苦的工作)。