为什么我的延迟任务没有触发 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 是完整的)。