当使用异步/等待与控制台应用程序时,为什么需要AsyncContext?

17
我在我的控制台应用程序中调用了一个异步方法。我不希望在awaitable任务完成之前应用程序短暂启动后就退出。看起来我可以这样做:
internal static void Main(string[] args)
{
    try
    {
        Task.WaitAll(DoThisAsync());
    }
    catch (Exception ex)
    {
        Console.Error.WriteLine(ex);
        throw;
    }
}

internal static async Task DoThisAsync()
{
    //...
}

但是根据Stephen Cleary的文章,似乎我不能这样做,而应该创建一些异步结束后返回的上下文(例如AsyncContext)。

尽管上面的代码有效,并且在Task.WaitAll(DoThisAsync());之后在主线程上返回,但为什么我需要使用自定义上下文呢?


也许是在使用线程池时出现的。线程池线程都是后台线程,只有主线程是前台线程。UI 应用程序会有一个主循环,它不允许它们在某些事情发生之前退出,而控制台应用程序通常没有这个循环。因此,如果您不阻止主线程等待某些内容,您的应用程序将简单地退出,并且您在线程池上执行的工作将消失。不过我不太确定。 - JustSomeGuy
正如@StephenCleary所提到的,这只是一种偏好。你阻塞线程的方式并不重要,你只需要意识到,如果你不以某种方式管理该线程,你的应用程序将退出(即使你的其他线程没有完成)。 - Brandon
@Brandon 嗯,这是有关系的。它们的功能不同,但当然可以使用任何一种方法编写工作程序。 - Servy
1个回答

30

这不是必须的,只是我的个人偏好。

您可以在Main中同步阻塞任务(使用Wait/Result/WaitAll)。语义略有不同; 特别是,如果异步代码失败,则Wait/Result/WaitAll将在AggregateException中包装异常,而AsyncContext则不会。

此外,AsyncContext特殊处理主线程; 它不会将连续体发送到线程池,而是将它们发送回该主线程(默认情况下; 您始终可以使用ConfigureAwait(false)来避免这种情况)。如果我正在编写“概念验证”控制台应用程序,我发现这很有用,因为AsyncContext的行为与UI上下文非常相似。

但归根结底,这只是一种偏好。


1
为什么 AsyncContext 需要这么多代码来防止 AggregateException?我看到了一个 TaskScheduler,TaskQueue(BlockingQueue),TaskFactory 和 AsyncContextSynchronizationContext。我看到了一个 AsyncContextThread,它说它执行 AsyncContext 的操作。我的意思是这里似乎有很多事情要做,但我没有找到一个好的解释说明实际发生了什么。我没有时间去尝试解密正在发生的事情。 - crush
1
你是否有一篇博客文章,可以解释一下底层发生了什么?我总是发现.Result.Wait()不好用,而且应该使用你的AsyncContext。为什么?AsyncContext有什么不同之处,使它成为更好的选择?在我看来,你是将任务安排在后台线程上运行,这样如果主线程退出,它们将继续运行直到完成?这是正确的吗? - crush
2
@crush:不,AsyncContext基本上充当一个消息循环,只有在所有异步操作完成时才退出。我不建议在一般情况下将其用作Result的替代品。在控制台的Main方法中,使用ResultAsyncContext都可以;在一般情况下,您应该使用await而不是Result,绝对不要使用AsyncContext - Stephen Cleary
1
@StephenCleary 感谢您的回复。我刚刚发现(阅读)了您2013年关于异步/等待最佳实践的文章,并且它真正澄清了一些事情。这段话很好地总结了我的情况:“对于那些只是“试水”异步编程的程序员来说,这是一个特别常见的问题,他们只将应用程序的一小部分转换为异步 API 并将其包装在同步 API 中,以使应用程序的其余部分与更改隔离。” 看起来 AsyncContext 可能存在来帮助程序员进行过渡? - crush
1
@crush:这是其中一种可能性,但由于可重入性的问题,我仍然不建议使用它。我有一篇更近期的关于“异步”棕地开发的文章(https://msdn.microsoft.com/en-us/magazine/mt238404.aspx),你可能会觉得有用。 - Stephen Cleary
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接