13

httpストリームからcsvドキュメントを読み取る次のメソッドがあります

public async IAsyncEnumerable<Line> GetLines([EnumeratorCancellation] CancellationToken cancellationToken)
{
    HttpResponseMessage response = GetResponse();

    using var responseStream = await response.Content.ReadAsStreamAsync();
    using var streamReader = new StreamReader(responseStream);
    using var csvReader = new CsvReader(streamReader);

    while (!cancellationToken.IsCancellationRequested && await csvReader.ReadAsync())
    {
        yield return csvReader.GetRecord<Line>();
    }
}

結果を使用する別の方法

var documentAsyncEnumerable = graphClient.GetLines(cancellationToken);
await foreach (var document in documentAsyncEnumerable.WithCancellation(cancellationToken))
{
    // Do something with document    
}

私の質問は、キャンセル トークンを 1 か所だけで使用する必要があるかどうかです。レコードを生成する前にキャンセルトークンを処理する必要がありますか、それとも IAsyncEnumerable.WithCancellation() は基本的に同じことをしていますか? あるとすれば違いは何ですか?

4

2 に答える 2

1

私の質問は、キャンセル トークンを 1 か所だけで使用する必要があるかどうかです。

キャンセルは協調的であるため、をキャンセルできるようにするには、 を提供するプロデューサーコードでキャンセルを実装する必要ありました。だから、プロデューサーは一箇所です。GetLinesIAsyncEnumerable<Line>

では、そのデータを使って何かを行うコードが という名前のメソッドを想像してみてください。それがconsumerConsumeLinesだとしましょう。あなたの場合、それは 1 つのコードベースである可能性がありますが、一般的に言えば、別のライブラリ、別のレポ、別のコードベースである可能性があります。

その他のコードベースでは、それらが同じ CancellationTokenであるという保証はありません。

では、消費者はどのようにキャンセルできますか?

Consumer は aCancellationTokenをに渡す必要がありますが、コンストラクトIAsyncEnumerable<T>.GetAsyncEnumeratorを使用している場合は直接公開されません。await foreach

これを解決するために、WithCancellation拡張メソッドが追加されました。ConfiguredCancelableAsyncEnumerableでラップすることにより、CancellationToken渡されたものを基になるものに転送するだけです。IAsyncEnumerable

いくつかの条件に応じて、これはCreateLinkedTokenSourceCancellationTokenを使用してプロデューサー内のものにリンクされるため、コンシューマーはプロデューサーに実装された協調キャンセルを使用してキャンセルできるため、消費だけでなく、生産もキャンセルできます。

レコードを生成する前にキャンセルトークンを処理する必要がありますか、それとも IAsyncEnumerable.WithCancellation() は基本的に同じことをしていますか? あるとすれば違いは何ですか?

はいプロデューサーコードでIsCancellationRequestedまたはThrowIfCancellationRequestedCancellationTokenのいずれかを使用して対応する必要があります。キャンセルは協調的です。プロデューサーで実装しないと、 の値の生成をキャンセルできません。IAsyncEnumerable

正確にいつキャンセルするか (譲る前または後) については、完全にあなた次第です。アイデアは、不必要な作業を避けることです。この精神で、不要な http リクエストの送信を避けるために、メソッドの最初の行でキャンセルを確認することもできます。

値の消費をキャンセルすることは、値の生成をキャンセルすることと必ずしも同じではないことに注意してください。

繰り返しになりますが、プロデューサーとコンシューマーは異なるコードベースにある可能性があり、異なるCancellationTokensから使用している可能性がありますCancellationTokenSources

それらの違いを一緒にリンクするには、 属性CancellationTokens を使用する必要があり ます。EnumeratorCancellation

私の記事EnumeratorCancellation: CancellationToken parameter from the generated IAsyncEnumerable.GetAsyncEnumerator will unconsumedの詳細な説明をお読みください。

于 2020-07-23T09:18:16.847 に答える