3

我知道最好的做法是避免 使用异步事件处理程序以外的任何方法,并且对于其他用例async void有相当强烈的专家意见。然而,我只是参与了关于方法有用性的简短讨论async void,我有几个问题:

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

3 回答 3

3

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

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

此外,您的方法要么有正确的签名,要么没有;事件处理程序不关心并且没有逻辑来专门检测或使用异步。

自定义调度程序将能够跟踪正在运行的任务,但不知道是否来自 async void 方法。无论如何,我认为这不是正确的解决方案——如果您发现自己需要跟踪 async void 方法,则需要重新考虑您的设计。

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

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

Async void 适用于调用者永远不需要关心方法调用的结果或在其他地方被通知结果的任何方法。这些情况应该非常罕见。

即发即弃可能就是这样一种情况,尽管我觉得人们经常滥用即发即弃,最终只是对自己隐藏了重要的错误。

于 2013-11-03T21:27:20.767 回答
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-void 方法转换为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 的使用并不可怕,但它是一种非常原始且不复杂的实现日志记录的方式。并且首先尝试实现它是非常不可取的,因为那里有许多免费的高质量实现。

于 2020-05-22T05:53:17.987 回答
0

它们对即发即弃的日志记录场景有用吗?

从概念上讲,我会这么说,但是如果一个任务有一个异常,并且没有通过等待它或访问它的异常属性来处理它,这在异步 void 方法中不会发生,它将破坏你的应用程序。所以我会避免这种情况。

于 2013-11-17T00:32:17.353 回答