gpt4 book ai didi

c# - ChannelReader.ReadAllAsync(CancellationToken) 实际上并未在迭代中取消

转载 作者:行者123 更新时间:2023-12-04 07:39:29 24 4
gpt4 key购买 nike

我一直在研究一项功能,该功能可以在 channel 中对耗时的工作进行排队,并在那里使用例如迭代 channel await foreach(var item in channel.Reader.ReadAllAsync(cancellationToken)) {...}

我原以为当通过 cancellationToken 请求取消时,ReadAllAsync 会在取消后的第一次迭代中抛出。

在我看来,情况并非如此。循环继续,直到处理完所有项目,然后它抛出一个 OperationCanceledException

至少可以说,这看起来有点奇怪。来自 ChannelReadergithub repo可以看到取消 token 标有 [EnumeratorCancellation] 属性,因此它应该被传递到围绕 yield return item; 生成的状态机(请纠正我如果我错了)。

我的问题是,这是 ReadAllAsync(CancellationToken) 的(某种程度上)正常行为,还是我遗漏了什么?

这是演示问题的简单测试代码 (try it on dotnetfiddle):

var channel = Channel.CreateUnbounded<int>();
for (int i = 1; i <= 10; i++) channel.Writer.TryWrite(i);
int itemsRead = 0;
var cts = new CancellationTokenSource();
try
{
await foreach (var i in channel.Reader.ReadAllAsync(cts.Token))
{
Console.WriteLine($"Read item: {i}. Requested cancellation: " +
$"{cts.Token.IsCancellationRequested}");

if (++itemsRead > 4 && !cts.IsCancellationRequested)
{
Console.WriteLine("Cancelling...");
cts.Cancel();
}
}
}
catch (OperationCanceledException)
{
Console.WriteLine($"Operation cancelled. Items read: {itemsRead}");
}

这是上面的输出。请注意项目获取在应该在中间取消后如何继续:

Read item: 1. Requested cancellation: False
Read item: 2. Requested cancellation: False
Read item: 3. Requested cancellation: False
Read item: 4. Requested cancellation: False
Read item: 5. Requested cancellation: False
Cancelling...
Read item: 6. Requested cancellation: True
Read item: 7. Requested cancellation: True
Read item: 8. Requested cancellation: True
Read item: 9. Requested cancellation: True
Read item: 10. Requested cancellation: True
Operation cancelled. Items read: 10

最佳答案

此行为是设计使然。我是复制粘贴Stephen Toub's response来自相关GitHub issue :

I would like to ask if this behavior is by design.

是的。已经有可供立即阅读的数据,因此实际上没有什么可以取消的。迭代器的实现就在this tight loop中。 :

while (TryRead(out T? item)) 
{
yield return item;
}

只要数据立即可用。一旦没有,它就会逃到外循环,外循环将检查取消。

也就是说,它可以更改。对于取消是否更可取,我没有强烈的意见;我希望这取决于用例。

关于c# - ChannelReader.ReadAllAsync(CancellationToken) 实际上并未在迭代中取消,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67569758/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com