一段时间以来,我一直试图了解 C# 用于异步代码的整个 async/await 模型。添加异步流(IAsyncEnumerable<T>
类型)看起来真的很酷,尤其是对于我正在编写的一些代码。
创建异步方法的最佳实践是包含一个CancellationToken
参数并将其用于取消异步进程。(理想情况下,通过将其传递给您方法中使用的底层异步方法调用。)
在创建返回异步流(an IAsyncEnumerable<T>
)的方法时,文档声明您的CancellationToken
参数应该用[EnumeratorCancellation]
属性修饰,然后使用该.WithCancellation()
方法IAsyncEnumerable<T>
本身传递的令牌。
但是,我一定是做错了什么,因为这仍然会触发警告:
CA2016:将 CancellationToken 参数转发给采用 1 的方法
无论我是否以更标准的方式执行此操作,都会出现此警告:
async IAsyncEnumerable<aThingo> GetFlibbityStream([EnumeratorCancellation] CancellationToken cancellationToken = default) {
aThingo slowValue = null;
do {
aThingo slowValue = await GetThatThingo(cancellationToken);
yield return slowValue;
while (slowValue != null);
}
async Task DoingStuff(CancellationToken cancellationToken) {
await foreach(var thng in ThingStreamCreator.GetFlibbityStream().WithCancellation(cancellationToken)) {
CrushThatThing(thng);
}
}
或者在我需要获取AsyncEnumerator
自身的地方(因为我需要一起迭代两个异步流,但不一定以相同的速率。)
async Task ValidatingThingsAsync(CancellationToken cancellationToken) {
await using IAsyncEnumerator<aThingo> srcEnumerator = source.ThingValidityAsyncStream(dateCutOff).GetAsyncEnumerator(cancellationToken);
... streamy stuff ....
}
我所有的异步流方法都有一个default
CancellationToken 值,这使它们成为可选参数。我认为我的问题的一部分可能是该WithCancellation()
方法适用于您已经拥有IAsyncStream<T>
但不一定将取消令牌传递给它的用例。但这并不完全有意义,感觉我要么过于频繁地传递取消令牌,要么不够(或者在我应该做另一个的时候做错了其中一个。)
在这些情况下,当我应该直接将取消令牌传递给异步流方法时,我是否只是在滥用WithCancellation()
和不必要地传递取消令牌?GetAsyncEnumerator()
基本上我不应该使用WithCancellation()
,也不应该传递任何东西,GetAsyncEnumerator()
而是应该在我的异步流方法上删除 CancellationToken 的默认值,并将令牌直接传递给它们。基本上我认为我对将 CancellationToken 传递给异步流并确定当时使用的正确方法的不同方法的数量感到困惑......