7

IEnumerableの期待されるパフォーマンスは何ですか?任意のIEnumerableを反復するパフォーマンスについて知る方法はないと言います。各反復はデータベースにヒットするか、Webサービス呼び出しを行う可能性があります。または、配列/リスト内の次の項目を返すだけの場合もあります。

それを考えると、「これは速い」ことを示す良い方法はありますか?たとえば、私と一緒に、T[]またはList<T>その代わりに、からへの移行が迅速になることIEnumerable<T>を知っています。(もちろん、列挙型にリスト/配列を返すように強制すると、他のパフォーマンス上の懸念が生じる可能性が あります。編集可能なセマンティクスも公開されます。)T[i]T[i+1]List<T>

逆に、 「これは遅い」ことを示す良い方法ではIQueryable<T>なく、戻ることでしょうか。IEnumerable<T>または多分IEnumerable<Task<T>>

のクライアントは、が劇的に異なるパフォーマンス特性を持つCことを知る方法がありません。IEnumerable<T>

class C
{
   readonly T[] m_data;
   public IEnumerable<T> ThisWillIterateQuickly { get { return m_data; } }

   public IEnumeralbe<T> ThisWillIterateSlowly
   {
      get
      {
         T retval = ... an expensive database call ...;
         yield return retval;
      }
   }

   public IQueryable<T> IsThisBetterForSlow { get { return ThisWillIterateSlowly; } }
   public T[] IsThisAGoodWayForFast { get { return m_data; } }
 }
4

4 に答える 4

3

逆に、IEnumerableの代わりにIQueryableを返すことは、「これは遅い」ことを示す良い方法でしょうか?

いいえ、IQueryable<T>固有のものIEnumerable<T>です...そしての問題は、リモートデータベースへのクエリなど、反復時に大きな副作用 が発生IEnumerable<T>Tする可能性があることです。IQueryable<T>

おかしいですね。

IEnumerable<T>おそらく、2番目のVSList<T>には間違いなくデータが含まれており、他の場所からデータを取得する必要がないVSについて質問する必要があります。

于 2012-06-07T15:07:47.087 に答える
2

反復に驚きが含まれないことを保証したい場合は、同意T[]します。配列から継承できないため、その列挙子をオーバーライドすることはできません。反復も副作用がなく、同じことは言えませんIEnumerable<T>

ただし、配列を公開することでこのメッセージが表現されることに同意しません。これは(私の意見では)より重要です。CheapIteration何かに名前を付け始めない限り、何かのパフォーマンスをコードで実際に表現することはできませんExpensiveIteration

コインの反対側では、アレイを使用して、オンデマンド反復のパフォーマンスの問題をアレイにデータを入力するポイントに移動するだけです。これは、アレイの内容を提供するものを完全に反復するため、パフォーマンスの問題を完全に解決することが保証されています。if反復が停止するIEnumerable<T>と、パフォーマンスの問題も停止します。最速のコードは、実行されないコードです。

于 2012-06-07T15:11:22.363 に答える
1

私は通常、「quick」列挙を返すためのプロパティと「slow」のためのメソッドを使用します。

あなたの問題は、可能な限り非同期のアプローチと設計を使用することに対する議論です。UIは応答性が高く、ユーザーは満足しているので、列挙にかかる時間は実際には関係ありません;-)

于 2012-06-07T15:59:33.573 に答える
1

これについてもう少し考えてみると、問題/質問は実際にはの動作/パフォーマンスに集中しているようですIEnumerator.MoveNext()Visual Studio 2012を使用して、IEnumeratorとの非同期バージョンを作成することができましたIEnumerable

public interface IAsyncEnumerator<T> : IDisposable
{
    Task<T> CurrentAsync { get; }
    Task<bool> MoveNextAsync();
    Task ResetAsync();
}

public interface IAsyncEnumerable<T>
{
    IAsyncEnumerator<T> GetAsyncEnumerator();
}

このアプローチの欠点は、言語サポートがあまりないことです。上記はでは機能しませんforeach。しかし、拡張方法は痛みを和らげることができます:

public static class EnumeratorExtensions
{
    public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
    {
        using (var enumerator = enumerable.GetEnumerator())
        {
            while (enumerator.MoveNext())
                action(enumerator.Current);
        }
    }

    public static async Task ForEachAsync<T>(this IAsyncEnumerable<T> enumerable, Action<T> action)
    {
        using (var enumerator = enumerable.GetAsyncEnumerator())
        {
            while (await enumerator.MoveNextAsync())
                action(await enumerator.CurrentAsync);
        }
    }
}
于 2012-06-08T14:47:37.590 に答える