gpt4 book ai didi

c# - 在循环中添加一个短暂的延迟可以防止它无限循环。为什么?

转载 作者:行者123 更新时间:2023-11-30 13:54:18 27 4
gpt4 key购买 nike

在使用 .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() 方法。

相关问题

When would I use Task.Yield()?

最佳答案

当你等待一个任务时,它首先检查任务是否完成,如果完成它只是继续执行并且永远不会返回给调用者。因此,调用 await DoWork(); 永远不会让您返回到调用方法,它只会在方法中同步继续。

当您删除延迟时,您现在拥有等同于拥有

public static async Task Loop()
{
while(true)
{
}
}

因此循环将永远循环,而不会将控制权交还给调用者。在这种情况下,您不知道是否会返回调用者,并且想保证不会永远循环,您可以将代码重写为

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.
}
}

关于c# - 在循环中添加一个短暂的延迟可以防止它无限循环。为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44081849/

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