迭代IEnumerable <string>导致严重的性能问题</string>

时间:2013-01-23 12:43:17

标签: c# performance

当我试图迭代IEnumerable类型时,我更不清楚for循环的性能发生了什么。

以下是导致严重性能问题的代码

foreach (IEdge ed in edcol)
{
    IEnumerable<string> row = 
        from r in dtRow.AsEnumerable()
        where (((r.Field<string>("F1") == ed.Vertex1.Name) && 
                (r.Field<string>("F2") == ed.Vertex2.Name))
            || ((r.Field<string>("F1") == ed.Vertex2.Name) &&
                (r.Field<string>("F2") == ed.Vertex1.Name)))
        select r.Field<string>("EdgeId");
    int co = row.Count();
    //foreach (string s in row)
    //{

    //}
    x++;
}

上层foreach(eddge中的IEdge)大约需要11000次迭代才能完成。 如果我删除行

,它会在几分之一秒内运行
int co = row.Count();

来自代码。

row.Count()在所有循环中的最大值为10。

如果我取消注释

//foreach (string s in row)
//{

//}

完成代码执行大约需要10分钟。

IEnumerable类型是否有如此严重的性能问题.. ??

2 个答案:

答案 0 :(得分:6)

这个答案是针对“我如何更快地加速”的隐含问题?抱歉,如果那不是实际上你所追求的,但......

您可以浏览行一次,按名称分组。 (我没有按照Marc的顺序进行排序 - 我只是在查询时查找两次:)

var lookup = dtRow.AsEnumerable()
                  .ToLookup(r => new { F1 = r.Field<string>("F1"),
                                       F2 = r.Field<string>("F2") });

然后:

foreach (IEdge ed in edcol)
{
    // Need to check both ways round...
    var first = new { F1 = ed.Vertex1.Name, F2 = ed.Vertex2.Name };
    var second = new { F1 = ed.Vertex2.Name, F2 = ed.Vertex1.Name };
    var firstResult = lookup[first];
    var secondResult = lookup[second];

    // Due to the way Lookup works, this is quick - much quicker than
    // calling query.Count()
    var count = firstResult.Count() + secondResult.Count();

    var query = firstResult.Concat(secondResult);

    foreach (var row in query)
    {
        ...
    }
}

答案 1 :(得分:1)

目前你有O(N * M)表现,如果N和M都很大,这可能是探测性的。我倾向于预先计算一些DataTable信息。例如,我们可以尝试:

var lookup = dtRows.AsEnumerable().ToLookup(
        row => string.Compare(row.Field<string>("F1"),row.Field<string>("F2"))<0
           ? Tuple.Create(row.Field<string>("F1"), row.Field<string>("F2"))
           : Tuple.Create(row.Field<string>("F2"), row.Field<string>("F1")),
        row => row.Field<string>("EdgeId"));

然后我们可以迭代:

foreach(IEdge ed in edCol)
{
    var name1 = string.Compare(ed.Vertex1.Name,ed.Vertex2.Name) < 0
           ? ed.Vertex1.Name : ed.Vertex2.Name;
    var name2 = string.Compare(ed.Vertex1.Name,ed.Vertex2.Name) < 0
           ? ed.Vertex2.Name : ed.Vertex1.Name;

    var matches = lookup[Tuple.Create(name1,name2)];
    // ...
}

(注意我为了方便而在那里强制使用升序字母对)