.NET 비동기/대기 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
Loop()
에서
bool completedOnTime = Task.Run(() => Loop()).Wait(TimeSpan.FromSeconds(1));
이 것 start a new thread을 필요로하지 않습니다
권장 해결 방법.
관련 질문
When would I use Task.Yield()?
시간 초과 작업이 완료되면'CancellationToken'을 사용하여'Task Loop()'을 멈추는가? 이 코드는'Task.Loop()'가 결코 멈추지 않을 것이기 때문에 여기에서 우스운 냄새가 난다. 그리고 멈추기 위해 구현 된 분명한 방법이 보이지 않는다. – Svek
사실, WhenAny에서 취소 토큰을 실제로 중지하려면 필요합니다. 그러나 문제는 취소 요청을 발행 할 기회가 없을 것입니다. 이것은 WhenAny가 결코 돌아 오지 않을 것을 기다리고 있기 때문입니다. –
@KonradJamrozik 실제로 문제가 더 올라가고 있습니다. 호출을'var loopTask = Loop();로 옮기면'WaitAny'가 아니라 결코 돌아 오지 않는'Loop'입니다. Task.WhenAny (loopTask, Task.Delay (TimeSpan.FromSeconds (1));)를 기다리고 디버거에서 볼 수 있습니다. –