猿问

在一定延迟后使用 async void 运行非 cpu 消耗任务是否好?

这是我的代码:


class StateManager

{

    private readonly ConcurrentDictionary<int, bool> _states = new ConcurrentDictionary<int, bool>();


    public void SetState(int id, bool state)

    {

        _states[id] = state;


        if (!state)

            RemoveLately(id);

    }


    private async void RemoveLately(int id)

    {

        await Task.Delay(10000).ConfigureAwait(false);

        _states.TryRemove(id, out _);


    }

}

我的目标是在一段时间后删除一个项目。我不想使用 Task.RunRemoveLately因为它可能被调用数千次。如果有的话,这种做法的缺点是什么?


慕侠2389804
浏览 81回答 2
2回答

慕斯王

我的目标是在一段时间后删除一个项目。那为什么不使用缓存呢?使用 async void 好吗?的准则async void是避免async void,除非您正在实现事件处理程序(或逻辑上类似于事件处理程序的东西)。所以这里真正的问题是:RemoveLately逻辑上是一个“事件处理程序”吗?我可以看到一个可以被认为是一个论点的论点;具体来说,TryRemove调用以响应计时器“事件”(&nbsp;Task.Delay)。所以我不会绝对地说这async void是错误的,但它确实有缺点。如果有的话,这种做法的缺点是什么?方法有一个主要问题async void:其他代码无法知道该方法何时完成。这个主要问题表现在几个方面:您的代码无法捕获或处理来自RemoveLately.&nbsp;由于无法观察async void方法的完成情况,因此也无法观察异常。因此,async void方法只是直接在其原始SynchronizationContext.&nbsp;在大多数情况下,这意味着方法中的异常async void会使应用程序崩溃。async void方法很难测试。这是因为单元测试代码无法知道async void方法何时完成。您的代码无法知道何时可以安全关闭(其中“关闭”的范围可能意味着“退出程序”或“处置StateManager”或介于两者之间的任何内容)。这是因为您的代码无法知道是否有async void工作仍在进行中。在这种只是从缓存中删除对象的特殊情况下RemoveLately,这应该可以忽略,但在一般情况下async void意味着应用程序永远不知道它何时“完成”。

千万里不及你

没有 async void (几乎)总是不好的(例如this)。正如 Stephen 在他的文章和此处的回答中所述,有一些理由需要使用异步 void 方法(即异步事件处理程序,除了 void 之外没有任何其他“返回”值)。斯蒂芬在他的回答中解释了您应该更改为异步任务的原因以及它们更好的原因。这就是为什么我建议您的方法应该如下所示:private async Task RemoveLately(int id)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; await Task.Delay(10000).ConfigureAwait(false);&nbsp; &nbsp; &nbsp; &nbsp; _states.TryRemove(id, out _);&nbsp; &nbsp; }作为一个小评论(如果我可以的话):如果你不确定选择什么和/或你可以选择Task(或Task<T>)或者async void然后尝试使用Task因为在几乎所有情况下(事件处理除外)你Task都比与async void。
随时随地看视频慕课网APP
我要回答