异步/等待与/不等待(发送并忘记)

20 浏览
0 Comments

异步/等待与/不等待(发送并忘记)

我有以下代码:

static async Task Callee()
{
    await Task.Delay(1000);
}
static async Task Caller()
{
    Callee(); // #1 忽略并忘记
    await Callee(); // #2 >1s
    Task.Run(() => Callee()); // #3 忽略并忘记
    await Task.Run(() => Callee()); // #4 >1s
    Task.Run(async () => await Callee()); // #5 忽略并忘记
    await Task.Run(async () => await Callee()); // #6 >1s
}
static void Main(string[] args)
{
    var stopWatch = new Stopwatch();
    stopWatch.Start();
    Caller().Wait();
    stopWatch.Stop();
    Console.WriteLine($"Elapsed: {stopWatch.ElapsedMilliseconds}");
    Console.ReadKey();
}

#1以最简单的方式忽略并忘记。#2仅仅等待。有趣的事情从#3开始。这些调用的深层逻辑是什么?

我知道在ASP.NET中使用忽略并忘记的注意事项,如这里所指出的。我之所以问这个问题,是因为我们正在将我们的应用迁移到服务Fabric,我们不能再使用HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => await LongMethodAsync());,建议是简单地将其替换为Task.Run

我看到Task.Run会运行一个新线程,那么#3和#5之间有什么区别呢?

0
0 Comments

在上述内容中,问题的产生原因是因为应用程序正在迁移到服务织物(Service Fabric),无法再使用HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => await LongMethodAsync()),建议是将其简单替换为Task.Run。然而,这是一个错误的建议。应该使用一个与Web前端通过队列分开的单独的后台进程。

问题的解决方法是,使用一个独立的后台进程,通过队列与Web前端分离。这样做的好处是,可以确保后台进程的执行不会影响到Web前端的性能和稳定性。另外,通过队列的方式可以实现任务的顺序执行,更加可控。

在上述内容中,还提到了一些关于异步调用的逻辑:

1. 在当前线程上启动异步方法,并忽略所有结果(包括异常)。

2. 在当前线程上启动异步方法,并异步等待其完成。这是调用异步代码的标准方式。

3. 在线程池线程上启动异步方法,并忽略所有结果(包括异常)。

4. 在线程池线程上启动异步方法,并异步等待其完成。

5. 与第3点完全相同。

6. 与第4点完全相同。

在这种情况下,根据问题描述,#3可能是一种可行的方式。然而,在我个人的建议中,我不推荐使用"fire and forget"。如果你正在使用ASP.NET之前的版本,并且可以接受偶尔丢失"fire and forget"任务而没有任何日志或通知,那么我会选择使用#3或#5的方式。

总结而言,问题的产生是因为迁移到服务织物,无法再使用原有的后台工作项方法。解决方法是使用独立的后台进程通过队列分离Web前端,以确保性能和稳定性。在选择异步调用方式时,如果可以接受任务丢失且无需日志或通知,则可以考虑使用#3或#5的方式。

0
0 Comments

"Fire and forget"是一种常见的编程模式,指的是在调用一个方法或执行一个任务后,不等待其完成而继续执行下一步操作。然而,这种模式存在一个严重的问题,就是可能会导致异常被吞没而无法捕获和处理。吞没异常,特别是致命异常,是异常处理中的致命错误。这样做只会导致程序在内存中产生更不可理解和重现的异常。因此,我们绝不能这样做。下面是两篇相关的好文章:

- http://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx

- http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET

使用线程时,很容易导致异常被吞没。实际上,我们需要额外的工作来避免吞没异常,并在线程完成后检查是否有异常发生。我们应该至少有一个后续任务来记录(可能是公开)异常。否则,我们将会为我们的"fire and forget"付出代价。

在ASP.NET中,特别是在Web应用程序中,也需要注意这个问题。下面是相关的文章:fire-and-forget-on-asp-net

希望这些内容对你有所帮助。

0