【问题标题】:Why does my delay task not trigger the Task.WaitAny()为什么我的延迟任务不触发 Task.WaitAny()
【发布时间】:2018-11-01 21:27:25
【问题描述】:

所以我有以下内容:

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 的回答表明了影响我的代码的副作用。这不一定能解决问题;只是告诉你你的问题出在哪里。不过,他添加了一条评论,其中包含一篇文章的链接,该链接确实可以帮助您解决问题。

【问题讨论】:

  • 您使用此 sn-p 的完整示例按预期工作这一事实意味着您已明确证明问题出在其他代码中。如果不知道该代码是什么,就不可能说出它为什么不起作用。
  • 如果您能提供minimal reproducible example,那就太好了。
  • 是的,我同意这两点。问题是针对“可能”做出的贡献。我同意这几乎可以肯定是一个副作用。但是我不知道应该尝试进一步隔离什么。如果我可以制作完整且可验证的示例,我希望我能很好地解决问题。
  • to what 'could' be contributing 这个问题太笼统了。没有必要问什么会起作用(尽管我在下面的回答是最可能的原因) - 如果您向我们展示代码,我们可以找出原因是什么
  • 虽然我完全理解你的观点,这太宽泛了;这是我花了很长时间试图孤立的东西。这篇文章很绝望,谢天谢地,道格拉斯的回答解决了我的问题。那就是说我仍然对你的@mjwills +1,因为我确实需要重新审视其他用例以确保。所以谢谢大家。

标签: c# .net task-parallel-library


【解决方案1】:

如果您从在原始线程(例如 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");
}

【讨论】:

  • 有趣的是,我在 2 个地方使用了它。在控制台应用程序中,任务永远不会超时并且工作正常。它在 winforms UI 中挂起......并尝试配置 await false 工作:) 我不知道谁反对这个,但它作为我的解决方案。谢谢
  • 人们倾向于对他们认为“开放式”问题及其答案投反对票。但是,您的问题包含足够的信息来确定此问题。在 WinForms 或 WPF 应用程序中使用 async–await 时,这实际上是 .NET 中非常常见的问题。根本原因是您大概在从包含上述代码的异步方法返回的任务上调用.Result.Wait()。有关说明,请参阅 Don't Block on Async Code
【解决方案2】:

但我看不出这种奇怪的行为会产生什么副作用......

您的longRunningTask 可能被分配了以下方法的返回值:

private static Task NewMethod()
{
    Thread.Sleep(11000);
    return Task.CompletedTask;
}

然后:

var myLongRunningTask = NewMethod();

因此,当您到达var readyTask = await 行时,11 秒睡眠(“长时间运行的任务”)已经已经发生(因为NewMethod 不是异步的),因此@ 987654326@ 立即返回(因为longRunningTask 已完成)。

【讨论】:

  • 在这种情况下,任务未完成且未重新分配。我在一个测试用例中确定了这一点。 WhenAny 也不返回。也就是说这是一个有趣的点,我将在其他情况下重新审视任务的活动
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-26
  • 1970-01-01
  • 1970-01-01
  • 2019-08-03
  • 2014-10-28
相关资源
最近更新 更多