0

当我尝试遍历 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(IEdge ed in edcol) 有大约 11000 次迭代要完成。如果我删除该行,它会在几分之一秒内运行

int co = row.Count();

从代码。

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

如果我取消注释

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

//}

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

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

4

2 回答 2

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)
    {
        ...
    }
}
于 2013-01-23T12:54:54.760 回答
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)];
    // ...
}

(请注意,为方便起见,我在那里强制执行升序字母对)

于 2013-01-23T12:54:46.943 回答