这是我的代码:
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
,因为它可能被称为数千次。
如果有的话,这种做法有什么弊端?
答案 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
好。