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回の反復があります。行を削除すると、数分の1秒で実行されます

int co = row.Count();

コードから。

row.Count()の最大値は、すべてのループで10です。

コメントを外すと

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

//}

コードの実行が完了するまで約10分かかります。

IEnumerableタイプには、このような深刻なパフォーマンスの問題がありますか?

4

2 に答える 2

6

この答えは、「どうすればこれをはるかに高速化できるか」という暗黙の質問に対するものです。それが実際にあなたが求めていたものではない場合はお詫びしますが...

名前でグループ化して、行を1回確認できます。(私はマークのように注文をしていません-クエリを実行するときに2回検索しているだけです:)

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 に答える