【问题标题】:Notify consumers when all tasks have completed without blocking the thread当所有任务完成时通知消费者而不阻塞线程
【发布时间】:2018-12-13 14:25:38
【问题描述】:

鉴于下面的代码,当所有任务都运行完成而不阻塞线程时,通知消费者最优雅的方式是什么?目前我有一个使用计数器的解决方案,该计数器在Execute(action) 之前递增并在Continuation()LogException() 之后递减。如果计数器为零,则可以安全地假设没有更多任务正在处理。

【问题讨论】:

  • 您是否尝试过启动 new Threadawaits 前一个 thread
  • ContinueWith 返回一个可以传递给Task.WhenAll 的任务,然后您可以等待对Task.WhenAll 的调用。

标签: c# .net multithreading asynchronous task


【解决方案1】:

首先,不要使用Task 构造函数。如果要在线程池线程中运行委托,请使用Task.Run。接下来,不要使用ContinueWith,使用await 为任务添加延续。以这种方式编写正确的代码要容易得多,尤其是在正确的错误处理方面。您的代码最有效地编写为:

try
{
    await Task.Run(() => Execute(action));
    Continuation();    
}
catch(Exception e)
{
    LogExceptions(e)
}
finally
{
    CustomLogging();
}

【讨论】:

  • 我同意你的观点,但请注意我们使用自定义 TaskScheduler。主要任务使用 OrderedTaskScheduler 进行调度,其余任务 (ContinueWith) 使用 SynchronizationContext 中的标准 TaskScheduler 进行调度
  • @zman 在这种方法中,所有的延续都在 UI 线程中运行。如果您想将实际工作与其他任务同步到队列中,我强烈建议您使用 like this 而不是任务调度程序。但是如果你真的想要的话,你可以使用Task.Factory.StartNew并提供一个任务调度器,虽然我不建议这样做。
  • 我能够用上面的代码替换现有代码,但不幸的是,仍然需要Task.Factory.StartNew,因为偶尔开发人员会交换“单线程”调度程序(即调度程序与当前相同)语境)。不确定这是否可以通过您建议的方法以优雅的方式实现。此外,仍然需要使用计数器的通知方法,但仅在 await 之前和 finally 中需要。
  • @zman 正如我告诉过你的,所显示的代码中的所有延续都已经在当前同步上下文中运行。在使用await 时,您几乎从不 需要显式编组到当前上下文,因为它默认发生。当您希望代码在当前上下文中运行时,您需要明确指出。使用StartNew 在当前上下文中运行代码表明你基本上每次都写错了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-27
  • 2021-02-16
  • 1970-01-01
  • 2010-11-06
相关资源
最近更新 更多