延迟一段时间后,使用异步void来运行非cpu消耗任务是否很好?

时间:2019-04-02 09:33:20

标签: c# asynchronous

这是我的代码:

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.Run用于RemoveLately,因为它可能被称为数千次。 如果有的话,这种做法有什么弊端?

2 个答案:

答案 0 :(得分:3)

  

我的目标是经过一段时间后删除项目。

那为什么不使用缓存呢?

  

使用异步void无效吗?

async void的准则是avoid async void unless you're implementing an event handler (or something that is logically like an event handler)。因此,这里的真正问题是:RemoveLately在逻辑上是“事件处理程序”吗?我可以看到一个论点可以被认为是一个论点。具体来说,TryRemove被调用以响应计时器“事件”(Task.Delay)。因此,我不会绝对地说async void在这里是错误的,但是它确实有缺点。

  

这种做法的弊端是什么?

async void方法存在一个主要问题:其他代码不知道该方法何时完成。

这个主要问题通过几种方式体现出来:

  • 您的代码无法捕获或处理RemoveLately中的异常。由于无法观察async void方法的完成,因此也无法观察异常。因此,async void方法只在原始SynchronizationContext上直接引发任何异常。在大多数情况下,这意味着async void方法中的异常将使应用程序崩溃。
  • async void方法很难测试。这是因为单元测试代码无法知道async void方法何时完成。
  • 您的代码无法知道何时可以安全关闭(“关闭”的范围可能表示“退出程序”或“处置StateManager”或两者之间的任何内容)。这是因为您的代码无法知道是否还有async void个工作仍在进行中。在这种特殊情况下,RemoveLately只是从缓存中删除一个对象,可以忽略它,但是在一般情况下,async void意味着应用程序永远不知道它何时“完成”。

答案 1 :(得分:0)

没有异步空缺(几乎)总是不好的(例如this)。 正如Stephen在其文章和此处的回答中所述,有一些原因具有异步void方法(即,异步事件处理程序除了void之外,没有其他任何“返回”值)。 Stephen应该在回答中解释为什么应该更改为异步Task以及为什么它们更好的原因。

这就是为什么我建议您的方法应如下所示:

private async Task RemoveLately(int id)
    {
        await Task.Delay(10000).ConfigureAwait(false);
        _states.TryRemove(id, out _);

    }

作为一个简短的评论(如果可以的话):如果不确定要选择什么和/或可以选择Task(或Task<T>)或async void,请尝试之所以使用Task是因为几乎在每种情况下(事件处理除外),Task都比async void好。