Linq是否会受到启动罚款?

时间:2018-11-05 00:57:25

标签: c# performance linq

我需要使用Linq查询或在应用程序中迭代100,000多个数据。速度至关重要。我写了一个测试,但没有得到预期的结果。基本上,我将完全相同的数据在一个循环中提供给两个不同的函数100次。这些功能是相似的,除了其中一个我使用多个Linq查询,而另一个我手动迭代数据以构建信息。代码如下:

Linq版本:

            //Get max and min of each
        double maxX = (from node in pointCloud
                       select node.Node.Value.X).Max();
        double maxY = (from node in pointCloud
                       select node.Node.Value.Y).Max();
        double maxZ = (from node in pointCloud
                       select node.Node.Value.Z).Max();
        double minX = (from node in pointCloud
                       select node.Node.Value.X).Min();
        double minY = (from node in pointCloud
                       select node.Node.Value.Y).Min();
        double minZ = (from node in pointCloud
                       select node.Node.Value.Z).Min();
        //Extract all the x, y and z values into arrays
        double[] x = (from node in pointCloud
                      select node.Node.Value.X).ToArray();
        double[] y = (from node in pointCloud
                      select node.Node.Value.Y).ToArray();
        double[] z = (from node in pointCloud
                      select node.Node.Value.Z).ToArray();

VS:

手册版本:

        //Get max and min of each
        double maxX = double.MinValue;
        double maxY = double.MinValue;
        double maxZ = double.MinValue;
        double minX = double.MaxValue;
        double minY = double.MaxValue;
        double minZ = double.MaxValue;

        List<double> x = new List<double>();
        List<double> y = new List<double>();
        List<double> z = new List<double>();

        foreach (NodeDistance<KDTreeNode<g.Point3d>> node in pointCloud)
        {
            maxX = msf.Max(maxX, node.Node.Value.X);
            maxY = msf.Max(maxY, node.Node.Value.Y);
            maxZ = msf.Max(maxZ, node.Node.Value.Z);
            minX = msf.Min(minX, node.Node.Value.X);
            minY = msf.Min(minY, node.Node.Value.Y);
            minZ = msf.Min(minZ, node.Node.Value.Z);
            x.Add(node.Node.Value.X);
            y.Add(node.Node.Value.Y);
            z.Add(node.Node.Value.Z);
        }

这是难题。当运行Linq版本时,第一次需要花费更长的时间。我在开始循环之前先启动秒表,然后在每次运行该功能后写下经过的时间。这是Linq函数运行的前5次:

00:00:00.0425169 (after 1st run)
00:00:00.0433850
00:00:00.0437312
00:00:00.0440666
00:00:00.0443969
....
00:00:00.1352192 (Total time for all 100 executions)

当我运行手动迭代的版本时,前五次是这样的:

00:00:00.0124269 (after 1st run)
00:00:00.0138497
00:00:00.0152502
00:00:00.0166348
00:00:00.0180180
....
00:00:00.1060389 (Total time for all 100 executions)

我将有30或40个不同的Linq查询,这些查询将在不同的时间运行。数据并没有全部排队,并且同一查询一遍又一遍地运行。如果我先运行一个Linq查询,然后再执行其他操作,则每次运行该查询实际上要花费0.04秒,那么该应用程序的运行速度将会非常慢。如果第一次运行任何Linq查询需要0.04秒,然后该应用不再发生该时间,那么使用Linq会更好。

有人在Linq和手动迭代方面有经验,并且在速度方面有一些指导吗?

2 个答案:

答案 0 :(得分:4)

我想不出“直线C#”至少不如LINQ快的情况。肯定有可能LINQ明显

因此,如果“速度”至关重要,那么最好不使用LINQ表达式。

重要要点:

  1. 请务必进行基准测试

    <=我不确定您上面的示例是否真的有效基准测试

  2. 请务必使用大数据集

    进行基准测试

    <=几年前,我遇到了一个看起来很无辜的LINQ表达式(由其他人编写),看上去不错,并且在少数项目中表现良好...但是速度却成倍地变慢,最终自爆出现堆栈溢出(无双关语)...包含1000项...

答案 1 :(得分:1)

您写道:

  

数据并没有全部排队,并且同一查询一遍又一遍地运行。

如果您将使用相同的输入多次执行LINQ查询,则明智的做法是保存结果。

var cityGroups = persons.GroupBy (person => person.City);

如果您查看references source of Enumerable.GroupBy,则会发现当您请求第一个元素时,会枚举完整的源序列以将各项放入“查找”表中。因此,如果再次枚举,将再次创建查找表:

因此,如果必须多次枚举,明智的做法是执行查询并将结果存储起来,以提高再次枚举时的效率:

var result = cityGroups.ToList();
foreach (var cityGroup in cityGroups)
{
    DoSomething(cityGroup};
}
foreach (var cityGroup in cityGroups)
{
     DoSomethinElse(cityGroup);
}

即使您不只是枚举,而是在其后添加一些LINQ语句,保存中间结果可能也是明智的:

var newYorkers = cityGroups.Where(cityGroup => cityGroup.Key == "New York").ToList();
var ghostTowns = cityGroups.Where(cityGroup => !cityGroup.Any()).ToList();

查找表将被创建两次。如果您在扩展结果之前执行ToList(),则查找表将仅创建一次

var result = cityGroups.ToList();
var newYorkers = result.Where(cityGroup => cityGroup.Key == "New York").ToList();
var ghostTowns = result.Where(cityGroup => !cityGroup.Any()).ToList();

我的建议是:如果您要一遍又一遍地执行相同的查询,请执行ToList(或“随您所需”)。