一个抽象的例子:有一个_reader,它异步读取数据。有一个 ,当应用程序退出时cancellationToken将变为:Cancel
while (!cancellationToken.IsCancellationRequested)
{
var readingTask = _reader.ReadAsync();
await Task.WhenAny(readingTask, Task.Delay(Timeout.Infinite, cancellationToken));
if (readingTask.IsCompletedSuccessfully)
{
var readResult = readingTask.Result;
// Обрабатываем readResult
}
}
假设循环已经执行了 40 次,会不会因为循环的每次迭代都会创建一个Task.Delay(Timeout.Infinite, cancellationToken)只有在 token 为 时才会完成的任务而导致内存被污染或性能下降Cancel?或者垃圾收集器(或其他人)会破坏这些无休止的任务吗?
像任何对象一样,当没有对它的引用时,Task 将被销毁。通常有两个参考:
您自己持有第一个引用(对于临时对象,只有 await 运算符“持有”它)。但是第二个链接一直存在,直到任务完成或取消。
因此,为了销毁一个任务,消费者通常有必要且足够的忘记它并取消工作。但每个个案可能都有自己的特点。
现在关于
Task.Delay. 对的引用Task.Delay由活动定时器持有,并在定时器被取消时丢失。因此,您所要做的就是取消 GC 收集对象的计时器:但是,从 判断
Timeout.Infinite,我看到这个任务是“永恒的”。在这里你可以不用Task.Delay:我注意到这里需要 using ,否则对 tcs 的引用将由取消令牌持有。
PS第三种方式来做你所追求的是这个:
这里
ContinueWith也创建了一个临时任务,该任务的链接一直保持到它完成或取消(但是,与选项不同的是Task.Delay,它在完成后立即结束readingTask)。我测试了退化的情况 - 根本没有
cancellationToken,在我看来这在这里并不重要。结果 - 尽管垃圾收集器工作,内存仍然结束。结论:
链接您可以在其中检查代码是否有效。