为什么我的延迟任务没有触发 Task.WaitAny()
Why does my delay task not trigger the Task.WaitAny()
所以我有以下内容:
if (await Task.WhenAny(myLongRunningTask, Task.Delay(9000)) != myLongRunnnigTask && !myLongRunningTask.IsFaulted)
{
Console.WriteLine("TimedOut");
}
else
{
Console.WriteLine("Completed");
}
当我完成任务时似乎工作正常;但是,如果我从未完成 运行 长的任务,那么它就会挂起,而不是在 9 秒后超时。甚至放入错误的测试以确保。
(注意:真正的代码不仅仅是命令行编写;但它甚至从未进入范围;虽然我也尝试过只编写命令行……没有改变。)
然而在 LinqPad 中做我认为完全相同的事情:
async void Main()
{
var Other = Task.Factory.StartNew(() => { Thread.Sleep(15000); });
if(await Task.WhenAny(Other, Task.Delay(4000)) != Other && !Other.IsFaulted) "TimedOut".Dump();
else "Completed".Dump();
Other = Task.Factory.StartNew(() => { Thread.Sleep(1000); });
if(await Task.WhenAny(Other, Task.Delay(4000)) != Other && !Other.IsFaulted) "TimedOut".Dump();
else "Completed".Dump();
}
那愉快地写TimedOut然后Completed。
第一个代码部分位于一个相当大的模块的深处。但是我看不出有什么可能会对这种奇怪的行为产生副作用......我可能会遗漏什么?
已接受答案的注释:
这里的问题是什么可能会产生副作用。 @Douglas 的回答指出了影响我的代码的副作用。这不一定能解决问题;只是告诉你问题出在哪里。但是,他很有帮助地在 帮助您修复它的文章中添加了带有 link 的评论。
如果您从在原始线程上执行延续的同步上下文(例如 WPF 或 WinForms UI)阻塞该异步方法,则可能会发生这种情况。尝试添加 ConfigureAwait(false)
并检查是否可以避免挂起:
var readyTask = await Task.WhenAny(myLongRunningTask, Task.Delay(9000)).ConfigureAwait(false);
if (readyTask != myLongRunnnigTask && !myLongRunningTask.IsFaulted)
{
Console.WriteLine("TimedOut");
}
else
{
Console.WriteLine("Completed");
}
But I can't see what might side-effect it to this odd behaviour...
您的 longRunningTask
可能被分配了 return 方法的值,例如:
private static Task NewMethod()
{
Thread.Sleep(11000);
return Task.CompletedTask;
}
之后:
var myLongRunningTask = NewMethod();
因此,当您到达 var readyTask = await
行时,第 11 秒睡眠 ('long running task') 已经发生(因为 NewMethod
不是异步的),因此 Task.WhenAny
return 立即(因为 longRunningTask
是完整的)。
所以我有以下内容:
if (await Task.WhenAny(myLongRunningTask, Task.Delay(9000)) != myLongRunnnigTask && !myLongRunningTask.IsFaulted)
{
Console.WriteLine("TimedOut");
}
else
{
Console.WriteLine("Completed");
}
当我完成任务时似乎工作正常;但是,如果我从未完成 运行 长的任务,那么它就会挂起,而不是在 9 秒后超时。甚至放入错误的测试以确保。
(注意:真正的代码不仅仅是命令行编写;但它甚至从未进入范围;虽然我也尝试过只编写命令行……没有改变。)
然而在 LinqPad 中做我认为完全相同的事情:
async void Main()
{
var Other = Task.Factory.StartNew(() => { Thread.Sleep(15000); });
if(await Task.WhenAny(Other, Task.Delay(4000)) != Other && !Other.IsFaulted) "TimedOut".Dump();
else "Completed".Dump();
Other = Task.Factory.StartNew(() => { Thread.Sleep(1000); });
if(await Task.WhenAny(Other, Task.Delay(4000)) != Other && !Other.IsFaulted) "TimedOut".Dump();
else "Completed".Dump();
}
那愉快地写TimedOut然后Completed。
第一个代码部分位于一个相当大的模块的深处。但是我看不出有什么可能会对这种奇怪的行为产生副作用......我可能会遗漏什么?
已接受答案的注释:
这里的问题是什么可能会产生副作用。 @Douglas 的回答指出了影响我的代码的副作用。这不一定能解决问题;只是告诉你问题出在哪里。但是,他很有帮助地在 帮助您修复它的文章中添加了带有 link 的评论。
如果您从在原始线程上执行延续的同步上下文(例如 WPF 或 WinForms UI)阻塞该异步方法,则可能会发生这种情况。尝试添加 ConfigureAwait(false)
并检查是否可以避免挂起:
var readyTask = await Task.WhenAny(myLongRunningTask, Task.Delay(9000)).ConfigureAwait(false);
if (readyTask != myLongRunnnigTask && !myLongRunningTask.IsFaulted)
{
Console.WriteLine("TimedOut");
}
else
{
Console.WriteLine("Completed");
}
But I can't see what might side-effect it to this odd behaviour...
您的 longRunningTask
可能被分配了 return 方法的值,例如:
private static Task NewMethod()
{
Thread.Sleep(11000);
return Task.CompletedTask;
}
之后:
var myLongRunningTask = NewMethod();
因此,当您到达 var readyTask = await
行时,第 11 秒睡眠 ('long running task') 已经发生(因为 NewMethod
不是异步的),因此 Task.WhenAny
return 立即(因为 longRunningTask
是完整的)。