8

Azure Storage クライアント ライブラリ 2.1 を使用して、テーブル ストレージの非同期クエリを作成しています。このコードを作成しました:

public async Task<List<TAzureTableEntity>> GetByPartitionKey(string partitionKey)
{
    var theQuery = _table.CreateQuery<TAzureTableEntity>()
                         .Where(tEnt => tEnt.PartitionKey == partitionKey);
    TableQuerySegment<TAzureTableEntity> querySegment = null;
    var returnList = new List<TAzureTableEntity>();
    while(querySegment == null || querySegment.ContinuationToken != null)
    {
        querySegment = await theQuery.AsTableQuery()
                                     .ExecuteSegmentedAsync(querySegment != null ?
                                         querySegment.ContinuationToken : null);
        returnList.AddRange(querySegment);
    }
    return returnList;
}

大規模なデータ セットが戻ってくると仮定して、Table Storage へのラウンド トリップが多数発生するようにします。私が抱えている問題は、データのセットを待っていて、それをメモリ内リストに追加して、さらにデータを待って、同じリストに追加して、さらにデータを待って、リストに追加する...などです。など。Task.Factory.StartNew() を通常の TableQuery にラップしないのはなぜですか? そのようです:

public async Task<List<TAzureTableEntity>> GetByPartitionKey(string partitionKey)
{
    var returnList = await Task.Factory.StartNew(() =>
                                                 table.CreateQuery<TAzureTableEntity>()
                                                .Where(ent => ent.PartitionKey == partitionKey)
                                                .ToList());
    return returnList;
}

このようにすると、SynchronizationContext をあまり往復していないように見えます。それとも本当に重要ですか?

質問を言い換えて編集

上記の 2 つのシナリオの違いは何ですか?

4

2 に答える 2

8

2 つの違いは、2 番目のバージョンではThreadPool、クエリの実行中ずっとスレッドがブロックされることです。これは、GUI アプリケーション (UI スレッド以外の場所でコードを実行することだけが必要な場合) では許容されるかもしれませんがasync、サーバー アプリケーションでのスケーラビリティの利点がすべて無効になります。

また、ラウンドトリップごとに最初のバージョンを UI コンテキストに戻したくない場合 (これは妥当な要件です)、使用するConfigureAwait(false)たびに次のように使用しますawait

querySegment = await theQuery.AsTableQuery()
                             .ExecuteSegmentedAsync(…)
                             .ConfigureAwait(false);

このように、最初の反復以降のすべての反復は (ほとんどの場合) ThreadPoolUI コンテキストではなくスレッドで実行されます。

ところで、2番目のバージョンでは、実際にはまったく必要ありません。await直接返すことができますTask

public Task<List<TAzureTableEntity>> GetByPartitionKey(string partitionKey)
{
    return Task.Run(() => table.CreateQuery<TAzureTableEntity>()
                               .Where(ent => ent.PartitionKey == partitionKey)
                               .ToList());
}
于 2013-10-28T12:28:36.627 に答える
3

これがあなたが探している答えかどうかはわかりませんが、それでも言及したいと思います:)。

すでにご存知かもしれませんが、2 番目の方法 ( を使用Task) は継続トークンを内部的に処理し、すべてのエンティティがフェッチされるとメソッドから終了しますが、1 番目の方法では一連のエンティティ (最大 1000 まで) をフェッチしてから、結果セットと継続トークン。

テーブルからすべてのエンティティを取得することに関心がある場合は、両方の方法を使用できますが、最初の方法では、いつでもループから抜け出す柔軟性が得られますが、2 番目の方法では得られません。したがって、最初の関数を使用すると、基本的にページネーションの概念を導入できます。

テーブルのデータを表示する Web アプリケーションを構築しているとします。さらに、テーブルに多数のエンティティ (100000 エンティティとしましょう) が含まれているとします。最初の方法を使用すると、1000 個のエンティティをフェッチして結果をユーザーに返すことができます。ユーザーが望む場合は、次の 1000 個のエンティティのセットをフェッチしてユーザーに表示できます。ユーザーが望む時間までそれを続けることができ、テーブルにデータがあります。2 番目の方法では、ユーザーは 100000 個のエンティティすべてがテーブルからフェッチされるまで待たなければなりません。

于 2013-10-28T09:30:27.983 に答える