使用 EnumeratorCancellation 返回 AsyncEnumerable 或循环 WithCancellation 有什么区别 [英] What's the difference between returning AsyncEnumerable with EnumeratorCancellation or looping WithCancellation

查看:48
本文介绍了使用 EnumeratorCancellation 返回 AsyncEnumerable 或循环 WithCancellation 有什么区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下方法可以从 http 流中读取 csv 文档

I have the following method that reads a csv document from a http stream

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>();
    }
}

以及其他地方使用结果的方法

and a method elsewhere that uses the result

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

我的问题是我应该在一个地方使用取消令牌吗?应该在产生记录之前对取消令牌采取行动还是 IAsyncEnumerable.WithCancellation() 基本上做同样的事情?如果有的话有什么区别?

My question is shouldn I use the cancellation token in just one place? Should the cancellation token be acted upon before yielding the record or is the IAsyncEnumerable.WithCancellation() basically doing the same thing? What is the difference if any?

推荐答案

在幕后,取消令牌无论如何都会传递给 GetAsyncEnumerator 方法,根据 来源

Under the hood the cancellation token is passed to GetAsyncEnumerator method anyway, according to the sources

namespace System.Collections.Generic
{
    public interface IAsyncEnumerable<out T>
    {
        IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default);
    }

    public interface IAsyncEnumerator<out T> : IAsyncDisposable
    {
        ValueTask<bool> MoveNextAsync();
        T Current { get; }
    }
}

你应该只使用一次cancellationToken,直接传递或者使用WithCancellation,这些方法都是一样的.WithCancellationIAsyncEnumerable 的扩展方法,接受一个 CancellationToken 作为参数(它使用与 ConfigureAwait 相同的模式)代码>).在 [EnumeratorCancellation] 的情况下,编译器生成代码,将令牌传递给 GetAsyncEnumerator 方法

You should use cancellationToken only once, passing directly or use WithCancellation, these methods are doing the same. WithCancellation is extension method for IAsyncEnumerable<T>, accepting a CancellationToken as an argument (it uses the same pattern with ConfigureAwait). In case of [EnumeratorCancellation] the compiler generate code that will pass the token to GetAsyncEnumerator method

两种不同方式的原因在MSDN 杂志

为什么有两种不同的方法呢?将令牌直接传递给方法更简单,但当你被任意处理时它不起作用来自其他来源的 IAsyncEnumerable 但仍然希望能够要求取消构成它的一切.在在极端情况下,将令牌传递给GetAsyncEnumerator,因为这样做可以避免烧入"单个可枚举将被多次枚举的情况:通过将它传递给 GetAsyncEnumerator,每个可以传递不同的令牌时间.

Why two different ways to do it? Passing the token directly to the method is easier, but it doesn’t work when you’re handed an arbitrary IAsyncEnumerable from some other source but still want to be able to request cancellation of everything that composes it. In corner-cases, it can also be advantageous to pass the token to GetAsyncEnumerator, as doing so avoids "burning in" the token in the case where the single enumerable will be enumerated multiple times: By passing it to GetAsyncEnumerator, a different token can be passed each time.

这篇关于使用 EnumeratorCancellation 返回 AsyncEnumerable 或循环 WithCancellation 有什么区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆