次の方法で共有


Azure SDK for .NET を使用した改ページ

この記事では、Azure SDK for .NET 改ページ位置付け機能を使用して、大規模なデータ セットで効率的かつ生産的に動作する方法について説明します。 改ページは、大きなデータ セットをページに分割する処理であり、コンシューマーがより少量のデータを反復処理しやすくします。 C# 8 以降では、 非同期 (非同期) ストリームを使用して非同期的にストリームを作成および使用できます。 非同期ストリームは、 IAsyncEnumerable<T> インターフェイスに基づいています。 Azure SDK for .NET では、IAsyncEnumerable<T> クラスを使用してAsyncPageable<T>の実装を公開しています。

この記事のすべてのサンプルは、次の NuGet パッケージに依存しています。

Azure SDK for .NET パッケージの最新ディレクトリについては、 Azure SDK の最新リリースを参照してください。

ページング可能な戻り値の型

Azure SDK for .NET からインスタンス化されたクライアントは、次のページング可能な型を返すことができます。

タイプ 説明
Pageable<T> ページで取得された値のコレクション
AsyncPageable<T> ページで非同期に取得される値のコレクション

この記事のほとんどのサンプルは、 AsyncPageable<T> 型のバリエーションを使用して非同期です。 I/O バインド操作に非同期プログラミングを使用することが理想的です。 完全なユース ケースは、Azure SDK for .NET の非同期 API を使用することです。これらの操作は HTTP/S ネットワーク呼び出しを表します。

を使用して AsyncPageable を反復処理する await foreach

AsyncPageable<T>構文を使用してawait foreachを反復処理するには、次の例を考えてみましょう。

async Task IterateSecretsWithAwaitForeachAsync()
{
    AsyncPageable<SecretProperties> allSecrets = client.GetPropertiesOfSecretsAsync();

    await foreach (SecretProperties secret in allSecrets)
    {
        Console.WriteLine($"IterateSecretsWithAwaitForeachAsync: {secret.Name}");
    }
}

前述の C# コードでは:

  • SecretClient.GetPropertiesOfSecretsAsync メソッドが呼び出され、AsyncPageable<SecretProperties> オブジェクトが返されます。
  • await foreach ループでは、各SecretPropertiesが非同期的に生成されます。
  • secret が具体化されると、その Name がコンソールに書き込まれます。

を使用して AsyncPageable を反復処理する while

AsyncPageable<T>構文が使用できない場合にawait foreachを反復処理するには、while ループを使用します。

async Task IterateSecretsWithWhileLoopAsync()
{
    AsyncPageable<SecretProperties> allSecrets = client.GetPropertiesOfSecretsAsync();

    IAsyncEnumerator<SecretProperties> enumerator = allSecrets.GetAsyncEnumerator();
    try
    {
        while (await enumerator.MoveNextAsync())
        {
            SecretProperties secret = enumerator.Current;
            Console.WriteLine($"IterateSecretsWithWhileLoopAsync: {secret.Name}");
        }
    }
    finally
    {
        await enumerator.DisposeAsync();
    }
}

前述の C# コードでは:

AsyncPageable ページを反復処理する

サービスからの値のページの受信を制御する場合は、 AsyncPageable<T>.AsPages メソッドを使用します。

async Task IterateSecretsAsPagesAsync()
{
    AsyncPageable<SecretProperties> allSecrets = client.GetPropertiesOfSecretsAsync();

    await foreach (Page<SecretProperties> page in allSecrets.AsPages())
    {
        foreach (SecretProperties secret in page.Values)
        {
            Console.WriteLine($"IterateSecretsAsPagesAsync: {secret.Name}");
        }

        // The continuation token that can be used in AsPages call to resume enumeration
        Console.WriteLine(page.ContinuationToken);
    }
}

前述の C# コードでは:

  • SecretClient.GetPropertiesOfSecretsAsync メソッドが呼び出され、AsyncPageable<SecretProperties> オブジェクトが返されます。
  • AsyncPageable<T>.AsPages メソッドが呼び出され、IAsyncEnumerable<Page<SecretProperties>>が返されます。
  • 各ページは、 await foreachを使用して非同期的に反復処理されます。
  • 各ページには、同期Page<T>.Valuesで反復処理されるIReadOnlyList<T>を表す一連のforeachがあります。
  • 各ページには、次のページを要求するために使用できる Page<T>.ContinuationTokenも含まれています。

System.Linq.AsyncAsyncPageable と共に使用する

System.Linq.Async パッケージには、型で動作する IAsyncEnumerable<T> メソッドのセットが用意されています。 AsyncPageable<T>IAsyncEnumerable<T>を実装するため、System.Linq.Asyncを使用してデータのクエリと変換を行うことができます。

に変換する List<T>

ToListAsyncを使用して、AsyncPageable<T>List<T>に変換します。 データが 1 つのページで返されない場合、このメソッドは複数のサービス呼び出しを行う可能性があります。

async Task ToListAsync()
{
    AsyncPageable<SecretProperties> allSecrets =
        client.GetPropertiesOfSecretsAsync();

    List<SecretProperties> secretList = await allSecrets.ToListAsync();

    secretList.ForEach(secret =>
        Console.WriteLine($"ToListAsync: {secret.Name}"));
}

前述の C# コードでは:

  • SecretClient.GetPropertiesOfSecretsAsync メソッドが呼び出され、AsyncPageable<SecretProperties> オブジェクトが返されます。
  • ToListAsync メソッドが待機され、新しいList<SecretProperties> インスタンスが具体化されます。

最初の N 個の要素を取得する

Takeは、Nの最初のAsyncPageable要素のみを取得するために使用できます。 Takeを使用すると、N項目を取得するために必要なサービス呼び出しが最も少なくなります。

async Task TakeAsync(int count = 30)
{
    AsyncPageable<SecretProperties> allSecrets =
        client.GetPropertiesOfSecretsAsync();

    await foreach (SecretProperties secret in allSecrets.Take(count))
    {
        Console.WriteLine($"TakeAsync: {secret.Name}");
    }
}

その他のメソッド

System.Linq.Asyncには、対応する同期Enumerableと同等の機能を提供する他のメソッドが用意されています。 このようなメソッドの例としては、 SelectWhereOrderByGroupByなどがあります。

クライアント側の評価に注意する

System.Linq.Async パッケージを使用する場合は、LINQ 操作がクライアントで実行されていることに注意してください。 次のクエリでは、 カウント するためだけにすべての項目をフェッチします。

// ⚠️ DON'T DO THIS! 😲
int expensiveSecretCount =
    await client.GetPropertiesOfSecretsAsync()
        .CountAsync();

警告

Whereなどの演算子にも同じ警告が適用されます。 サーバー側のフィルター処理、集計、またはデータのプロジェクション (使用可能な場合) を常に優先します。

監視可能なシーケンスとして

System.Linq.Async パッケージは主に、IAsyncEnumerable<T> シーケンスに対してオブザーバー パターン機能を提供するために使用されます。 非同期ストリームはプルベースです。 項目が反復処理されると、次に使用可能な項目が プルされます。 このアプローチは、プッシュベースのオブザーバー パターンと並置されています。 アイテムが使用可能になると、オブザーバーとして機能するサブスクライバーに プッシュ されます。 System.Linq.Async パッケージには、ToObservableIAsyncEnumerable<T>に変換できるIObservable<T>拡張メソッドが用意されています。

IObserver<SecretProperties>実装を想像してみてください。

sealed file class SecretPropertyObserver : IObserver<SecretProperties>
{
    public void OnCompleted() =>
        Console.WriteLine("Done observing secrets");

    public void OnError(Exception error) =>
        Console.WriteLine($"Error observing secrets: {error}");

    public void OnNext(SecretProperties secret) =>
        Console.WriteLine($"Observable: {secret.Name}");
}

ToObservable拡張メソッドは次のように使用できます。

IDisposable UseTheToObservableMethod()
{
    AsyncPageable<SecretProperties> allSecrets =
        client.GetPropertiesOfSecretsAsync();

    IObservable<SecretProperties> observable = allSecrets.ToObservable();

    return observable.Subscribe(
        new SecretPropertyObserver());
}

前述の C# コードでは:

  • SecretClient.GetPropertiesOfSecretsAsync メソッドが呼び出され、AsyncPageable<SecretProperties> オブジェクトが返されます。
  • ToObservable() メソッドは、AsyncPageable<SecretProperties> インスタンスで呼び出され、IObservable<SecretProperties>が返されます。
  • observableがサブスクライブされ、オブザーバー実装が渡され、サブスクリプションが呼び出し元に返されます。
  • サブスクリプションは IDisposableです。 破棄されると、サブスクリプションは終了します。

ページング可能な反復処理

Pageable<T>は、通常のAsyncPageable<T> ループで使用できる同期バージョンのforeachです。

void IterateWithPageable()
{
    Pageable<SecretProperties> allSecrets = client.GetPropertiesOfSecrets();

    foreach (SecretProperties secret in allSecrets)
    {
        Console.WriteLine($"IterateWithPageable: {secret.Name}");
    }
}

重要

この同期 API は使用可能ですが、エクスペリエンスを向上するために、非同期 API の代替手段を使用してください。

こちらも参照ください