重新访问异步void方法的用例

时间:2013-11-02 23:03:41

标签: c# .net asynchronous task-parallel-library async-await

我知道best practice is to avoid async void方法除了异步事件处理程序外,还有其他用例的strong expert opinion。然而,我只是参与了关于async void方法的有用性的简短discussion,我有几个问题:

  • 框架如何跟踪待处理的async void方法,包括事件处理程序?是否有可能获取当前列表或取消它们(已编辑:可能通过安装自定义SynchronizationContext进行跟踪)?
  • 它们对于即发即弃的日志记录是否有用?我认为它们实际上可能是,只要在方法开头保留了正确的时间戳,它仍然存在同步执行。

3 个答案:

答案 0 :(得分:2)

  

框架如何跟踪挂起的异步void方法,包括事件处理程序?

框架没有做任何特殊的事情来跟踪异步void方法。它们就像任何其他异步方法一样。

此外,您的方法要么具有适当的签名,要么没有;事件处理程序并不关心,也没有逻辑可以专门检测或使用异步。

自定义调度程序将能够跟踪正在运行的任务,但如果是来自异步void方法,则没有任何特定知识。我不认为这是正确的解决方案 - 如果你发现自己需要跟踪异步void方法,你需要重新考虑你的设计。

  

对于即发即弃的日志记录方案,它们是否有用?我认为它们实际上可能是,只要保留正确的时间戳

我不知道你的时间戳是什么意思?

对于调用者永远不需要关心方法调用的结果,或者在其他地方通知结果的任何方法,异步void都可以。这些案件应该非常罕见。

虽然我觉得人们经常滥用“一劳永逸”而最终只是隐藏了自己的重要错误。

火灾和遗忘可能就是这样一种情况。

答案 1 :(得分:1)

关于日志记录方案,这是两种方案,其中async-void适用于第一种方案,而不适用于第二种方案。

1)记录长时间运行的结果:

public static async void LogCompletion(Task operation, string title)
{
    try
    {
        await operation.ConfigureAwait(false);
        Log.Info($"{title} completed succesfully");
    }
    catch (Exception ex)
    {
        Log.Error($"{title} failed", ex);
    }
}

此用法类似于异步事件处理程序,因为异步操作的完成在概念上类似于引发事件。因此,此方法实质上是“处理”特定任务的完成“事件”。将此异步无效方法转换为async Task LogCompletionAsync方法不会带来很多好处。确实,LogCompletion方法内的异常将使进程崩溃,但是发生异常的唯一可能性是如果抛出Log.Error。但是,如果您的日志记录框架开始引发异常,那么您的应用程序将无法长期存活。而且,越早了解它越好,开始尽快搜索更好的日志记录框架。

2)本身记录:

public static async void Log(string message)
{
    try
    {
        await File.AppendAllTextAsync(GetLogFilePath(),
            DateTime.Now.ToString() + " " +  message + "\r\n");
    }
    catch { }
}

此用法类似于以一劳永逸的方式调用异步方法。尽管这不是async-void的可怕用法,但它通常是实现日志记录的一种非常原始且不复杂的方法。而且,一开始尝试实施它是非常不明智的,因为那里有many个免费的高质量实现。

答案 2 :(得分:0)

  

它们对于即兴发射的记录是否有用?

从概念上讲,我会这么说,但是如果一个任务有一个例外并且它没有通过等待它或访问它的异常void属性方法中没有发生的异常属性来处理它会撕裂关闭你的申请。 所以我会避免这种情况。