2010-05-31 66 views
2

我有两种方法的程序。第一种方法需要两个数组作为参数,并执行,其中来自一个阵列被有条件地写入到其它,像这样值的运算:关于多线程,锁和多核处理器的多部分问题(multi^3)

void Blend(int[] dest, int[] src, int offset) 
{ 
    for (int i = 0; i < src.Length; i++) 
    { 
     int rdr = dest[i + offset]; 
     dest[i + offset] = src[i] > rdr? src[i] : rdr; 
    } 
} 

第二种方法通过他们创建int阵列和迭代的两套独立的这样一组的每个阵列是Blend版与另一组的每个阵列,像这样:

void CrossBlend() 
{ 
    int[][] set1 = new int[150][75000]; // we'll pretend this actually compiles 
    int[][] set2 = new int[25][10000]; // we'll pretend this actually compiles 
    for (int i1 = 0; i1 < set1.Length; i1++) 
    { 
     for (int i2 = 0; i2 < set2.Length; i2++) 
     { 
      Blend(set1[i1], set2[i2], 0); // or any offset, doesn't matter 
     } 
    } 
} 

第一个问题:由于此之路探寻是并行的明显的候选人,是它的本质是线程安全的?这似乎是否定的,因为我可以设想一个场景(不太可能,我认为)一个线程的更改由于不同的线程〜同时操作而丢失。

如果没有,就这样:

void Blend(int[] dest, int[] src, int offset) 
{ 
    lock (dest) 
    { 
     for (int i = 0; i < src.Length; i++) 
     { 
      int rdr = dest[i + offset]; 
      dest[i + offset] = src[i] > rdr? src[i] : rdr; 
     } 
    } 
} 

是一个有效的解决?

第二个问题:如果是这样,使用这种锁的可能性能成本是多少?我认为,如果某个线程尝试锁定当前被另一个线程锁定的目标数组,则第一个线程会阻塞,直到锁被释放,而不是继续处理某些内容。

另外,它需要多少时间才能获得锁定?纳秒级别还是比这还差?这会成为像这样的主要问题吗?

第三个问题:我将如何最好的办法这个问题,将充分利用多核处理器的(这是基于潜在的错误的假设,一个多线程的解决办法不是速度多线程方式在单个核心处理器上执行此操作)?我猜想我希望每个核心都有一个线程运行,但我不知道这是否正确。

+0

您将在<100ns内获得无争议的锁定。 – Rusty 2010-06-05 22:18:58

+0

看看PLINQ。 [了解PLINQ中的加速](http://msdn.microsoft.com/en-us/library/dd997399%28v=VS.100%29.aspx) – Rusty 2010-06-05 22:26:43

回答

3

与CrossBlend的潜在争用是set1 - 混合的目的地。与使用锁相比,与您正在进行的工作量相比,这将比较昂贵,而不是安排每个线程在它自己的目的地上工作。这是一个给定的目标(set1中某个索引处的数组)由给定任务拥有。这是可能的,因为结果独立于CrossBlend处理阵列的顺序。

然后每个任务应该只运行CrossBlend中的内部循环,并且该任务使用dest数组(index1)的索引参数化为使用(或指数范围)

您也可以并行化Blend方法,因为每个索引都是独立于其他索引计算的,因此在那里没有争用。但是在今天的机器上,使用< 40个内核,您只需通过CrossBlend方法即可获得足够的并行性。

要为N个核多核您可以

  1. 有效地运行,划分问题分为N个部分。鉴于set1相对于核心数量相当大,您可以将set1划分为N个范围,并将每个索引范围传递给运行内部CrossBlend循环的N个线程。这会给你相当好的并行性,但它不是最优的。(有些线程会更快完成,最终无需做任何工作。)
  2. 更复杂的方案是使CrossBlend内部循环的每次迭代都成为一个单独的任务。有N个队列(对于N个核心),并将这些任务分配到队列中。启动N个线程,每个线程从队列中读取任务。如果一个线程队列变为空,它将从其他线程的队列中获取一个任务。

第二种方法是最适合于尺寸不规则的任务,或者被用于其他任务的系统,所以一些核心可能是时间的其他进程之间进行切换,所以你不能指望在等量工作完成大致相同的时间在不同的内核上。

第一种方法编码简单得多,并且可以提供很好的并行性。

+0

我忘了我的问题的另一部分:在C#中,我怎么能确定核心数量? – MusiGenesis 2010-05-31 11:42:04