11

等待发送非必要指标对我来说毫无意义,因为它会在每次调用后端 dotnet 核心服务时增加延迟(等待服务器的响应),每次客户端调用可能会发生多次。尽管如此,在失败时记录错误仍然很重要(尽管我不需要抛出它,因为度量标准的失败不应该影响服务)。

我发现了多种方法。以下是以 FireAndForget 方式调用的方法:

public async Task FireAndForget()
{
    try{ await sendTheMetric(); } // Try catch on the await, to log exceptions
    catch(Exception e){ logger.debug(e) }
}

方法一:去掉await。

FireAndForget(); // No await in front of the call

方法 2:对我来说似乎类似于方法 1,因为我们不等待 Task.Factory.StartNew 调用。

Task.Factory.StartNew(async () => await MyAsyncTask());

方法 3:作为工作项在 ThreadPool 上排队。

ThreadPool.QueueUserWorkItem(async o => await FireAndForget());

我很难找到应该将哪个用于 Fire 而忘记发送非必要指标的调用。我的目标是在每次发送指标时不增加对我的服务的每次调用的延迟。当度量标准发送失败时记录错误很重要,但它永远不应该重新抛出。线程上下文对于任务的执行并不重要。任务应该总是,或者至少几乎总是,被完成。

哪一个是满足需求的最佳实践?还是它们都一样?

注意:我没有包括async void,因为它看起来有风险(如果发生异常,它可能会崩溃,因为没有任务会包装它)。

4

2 回答 2

14

希望这不会使水变得浑浊,但有第四个选项(根据我的阅读)正在成为一个更被接受的选项。

从 C#7.0 开始,您可以选择对此类实例使用丢弃。

_ = FireAndForget();

这实质上表明不需要该任务,因此不需要返回值。似乎比方法 1 更推荐,因为这意味着您明确指出它是“一劳永逸”(这不那么模棱两可,看起来不像是编码错误)。

于 2020-05-15T13:38:08.047 回答
2

Method2 似乎也不错,变化不大

      Task.Factory.StartNew(async () => await MyAsyncTask())
        .ContinueWith(t => {
            switch (t.Status)
            {
                case TaskStatus.Created:
                case TaskStatus.WaitingForActivation:
                case TaskStatus.WaitingToRun:
                case TaskStatus.Running:
                case TaskStatus.WaitingForChildrenToComplete:
                case TaskStatus.RanToCompletion:
                    break;
                case TaskStatus.Canceled:
                case TaskStatus.Faulted:
                    //Log error message if any 
                    break;
                default:
                    break;
            }
        });

这样,您仍然可以触发并忘记记录错误消息(如果有)。

于 2020-05-15T13:57:47.307 回答