Kon*_*zik 3 c# asynchronous task infinite-loop async-await
在使用.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;
}
}
Run Code Online (Sandbox Code Playgroud)
背景
实际的程序有,while(!done)但由于一个错误done从未设置为true.循环进行多次await调用.该Task.WhenAny呼叫是在单元测试中以防止Loop()挂起.如果我故意引入一个bug,大多数时候测试确实会超时,但有时候它仍然会挂起.
建议的解决办法,不需要Task.Delay在Loop()
bool completedOnTime = Task.Run(() => Loop()).Wait(TimeSpan.FromSeconds(1));
Run Code Online (Sandbox Code Playgroud)
相关问题
等待任务时,它首先检查任务是否完成,如果完成,它只是继续执行,永远不会返回给调用者.因此,调用await DoWork();永远不会使您返回到调用方法,它将在方法中同步继续.
当您删除延迟时,您现在具有相应的延迟
public static async Task Loop()
{
while(true)
{
}
}
Run Code Online (Sandbox Code Playgroud)
因此循环将永远循环,而不会将控制权交还给调用者.在这样的情况下,你不知道你是否会回到调用者,并且你想保证你不会永远循环,你可以将你的代码重写为
public static async Task Loop()
{
while(true)
{
var workTask = DoWork();
if(workTask.GetAwaiter().IsCompleted) //This IsCompleted property is the thing that determines if the code will be synchronous.
await Task.Yield(); //If we where syncronous force a return here via the yield.
await workTask; //We still await the task here in case where where not complete, also to observe any exceptions.
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
542 次 |
| 最近记录: |