【发布时间】:2017-10-20 06:43:58
【问题描述】:
在使用 .NET async/await API 时,我遇到了一个好奇心:循环忽略了用作超时的延迟,直到我在循环中添加了一个短暂的延迟。这是如何运作的?不是最直观的行为!
完整程序:
using System;
using System.Threading.Tasks;
public class Program
{
public static void Main(String[] args)
{
Task.Run(async () =>
{
await Task.WhenAny(Loop(), Task.Delay(TimeSpan.FromSeconds(1)));
Console.WriteLine("Timed out!");
})
.Wait();
}
public static async Task Loop()
{
while(true)
{
// Commenting this out makes the code loop indefinitely!
await Task.Delay(TimeSpan.FromMilliseconds(1));
// This doesn't matter.
await DoWork();
}
}
public static async Task DoWork()
{
await Task.CompletedTask;
}
}
背景
实际程序有while(!done),但由于一个错误,done 从未设置为true。该循环进行了许多await 调用。 Task.WhenAny 调用在单元测试中,以防止 Loop() 挂起。如果我在大多数情况下故意引入错误,测试确实会超时,但有时它仍然会挂起。
在Loop() 中不需要Task.Delay 的建议解决方法
bool completedOnTime = Task.Run(() => Loop()).Wait(TimeSpan.FromSeconds(1));
这将start a new thread 执行Loop() 方法。
相关问题
【问题讨论】:
-
看起来有些不对劲,您是否考虑过在超时任务完成时使用
CancellationToken来停止您的Task Loop()?这里的代码闻起来很有趣,因为您的Task.Loop()永远不会停止,而且我看不到有明确的方法来阻止它。 -
你是对的,实际上需要WhenAny 中的取消令牌来停止它。但是,问题是,我们永远没有机会发出取消请求。这是因为 awaitWhenAny 永远不会返回。
-
@KonradJamrozik 实际上问题更严重,永远不会返回的是
Loop,而不是WaitAny,如果您将该调用移至var loopTask = Loop(); await Task.WhenAny(loopTask, Task.Delay(TimeSpan.FromSeconds(1)));,您可以在调试器中看到它.
标签: c# asynchronous async-await task infinite-loop