如何将For循环更改为PLINQ语法

本文关键字:PLINQ 语法 循环 For | 更新日期: 2023-09-27 18:11:28

我的代码有一个真正的问题,它非常慢,使它无用。我必须交付我的结果下周和这个代码,它需要超过4周!当这段代码计算流体运动时,我们要处理超过100万个单元格。因此,我的主For循环(顺序很重要)需要大量的计算,现在每个输出都需要12分钟。想象一下,我至少需要5000个输出!

谁能帮我提高计算速度?或你能帮我理解如何改变For循环为PLINQ语法吗?

我很沮丧

//implementation of time nt = 1,000,000
    For (int t=0; t<nt; t++)
    { 
// main calculations, 2 dimensional   
    for (int i = 0; i < nx; i++)
        {
            for (int j = 0; j < ny; j++)
            {
                if (!Cells[i, j, 0].IsVirtual)
                {
                    // calculate x velocity - nx = 1,000,000 & ny = 1,000,000
                    // calculate y velocity
                    // Data for each (i,j) affect (i+1,j+1)
            }
         }
     }
    }

如何将For循环更改为PLINQ语法

为了能够使用PLINQ,您需要将二维for循环更改为可以处理的元素序列(例如IEnumerable<T>)。您可以使用以下代码将x和y值创建为一个序列:

var indices = Enumerable.Range(0, nx).SelectMany(
  _ => Enumerable.Range(0, ny),
 (x, y) => new { X = x, Y = y }
);

然后可以使用Where过滤索引序列:

indices.Where(index => !Cells[index.X, index.Y, 0].IsVirtual)

然后您可以使用Select投影索引来创建结果:

var results = indices
  .Where(...)
  .Select(index => new { index.X, index.Y, Result = ... });

当你把你的代码转换成这种形式,并确保它在一个小的数据集上工作时,你可以使用PLINQ在Select中并行运行计算,插入AsParallel:

var results = indices
  .Where(...)
  .AsParallel()
  .Select(index => new { index.X, index.Y, Result = ... })
  .ToList();
在你的问题中,你谈到了秩序的重要性。通过使用AsOrdered: ,您可以确保生成的结果与输入索引保持相同的顺序。
var results = indices
  .Where(...)
  .AsParallel()
  .AsOrdered()
  .Select(index => new { index.X, index.Y, Result = ... })
  .ToList();

然而,for循环的"主体"仍然是并行执行的,没有特定的顺序。当ToList创建列表时,只有对最终结果进行排序。如果你提到的顺序的重要性意味着你在for循环体中使用了可变状态,那么你将不能使用PLINQ。

这种使用PLINQ的方法不是特别有效。如果您必须处理1,000,000个单元格,那么该代码将分配1,000,000个对象来存储单元格的索引。然而,似乎是处理时间而不是内存分配和垃圾收集限制了你的计算。

如果你使用Parallel.For之类的东西来并行化你的计算,你可以避免分配的开销,但你将使用TPL而不是PLINQ。

使用下面的代码,您可以使用您的集合代替列表。如果你需要任何帮助,请告诉我:

List<string> lst = new List<string>();
foreach (var item in lst.AsParallel())
{
    foreach (var data in item)
    {
    }
}