异步/等待有/无等待(即发即弃)
Posted
技术标签:
【中文标题】异步/等待有/无等待(即发即弃)【英文标题】:Async/await with/without awaiting (fire and forget) 【发布时间】:2017-09-05 10:51:56 【问题描述】:我有以下代码:
static async Task Callee()
await Task.Delay(1000);
static async Task Caller()
Callee(); // #1 fire and forget
await Callee(); // #2 >1s
Task.Run(() => Callee()); // #3 fire and forget
await Task.Run(() => Callee()); // #4 >1s
Task.Run(async () => await Callee()); // #5 fire and forget
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 中使用 fire'n'forget 警告,正如 here 所指出的那样。我问这个,因为我们正在将我们的应用程序移动到服务结构,我们不再可以使用HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => await LongMethodAsync());
,建议只是用Task.Run
替换它。
我看到Task.Run
运行了一个新线程,那么#3 和#5 有什么区别?
【问题讨论】:
请定义“有趣的东西”。Task.Run
使用单独的线程。
Fire-and-forget with async vs "old async delegate"的可能重复
Tl;如果你想一劳永逸,请不要使用async
/await
。
不,它不是@Christopher,它是异步编程,而不是多线程编程。 Aync 重用空闲的线程,多线程 (Task
) 创建了新线程来独立于主线程进行处理。
换句话说,async 和 await 是不同的,你在单独的线程中运行新的异步方法等待某事,它不会冻结你的主线程因为它本身是异步的
【参考方案1】:
我问这个,因为我们正在将我们的应用程序移动到服务结构,我们不再可以使用 HostingEnvironment.QueueBackgroundWorkItem(async cancelToken => await LongMethodAsync());建议是简单地将其替换为 Task.Run。
这是个坏建议。你应该使用separate background process separated from your web frontend by a queue。
调用背后的深层逻辑是什么?
-
在当前线程上启动异步方法。忽略所有结果(包括例外)。
在当前线程上启动异步方法。异步等待它完成。这是调用异步代码的标准方式。
在线程池线程上启动异步方法。忽略所有结果(包括例外)。
在线程池线程上启动异步方法。异步等待它完成。
与#3 完全相同。
与#4 完全相同。
【讨论】:
那么#3 是“正确”的方法吗?试图根据我的问题在这里确定:***.com/questions/67243044/… @Terry:我完全不推荐“一劳永逸”。如果您使用的是 ASP.NET pre-Core,并且偶尔会丢失“即发即弃”的工作而没有任何日志或工作丢失通知,那么我会说 #3 或 #5 就可以了。 【参考方案2】:“26. “一劳永逸”很好,前提是你永远不会真正忘记。” Maxim 26.
如果您执行任何类型的“一劳永逸”的场景,您将面临吞下异常的巨大风险。吞下任何异常——尤其是致命的异常——是异常处理的致命罪过。你最终得到的只是内存中的一个程序,它会产生更难以理解和可重现的异常。所以永远不要开始。这里有两篇关于母校的好文章:
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
众所周知,Full on Threads 能够吞下异常。事实上,你必须努力不吞下它们,然后在它们完成后检查它们是否有一个。您应该至少有一些后续任务来记录(以及可能的暴露)异常。不然你真的会后悔那次“一劳永逸”。
希望对您有所帮助。
【讨论】:
这句话太棒了。 对于 ASP 添加:fire-and-forget-on-asp-net以上是关于异步/等待有/无等待(即发即弃)的主要内容,如果未能解决你的问题,请参考以下文章
演员模型不是一种反模式吗,因为即发即弃的风格迫使演员记住一个状态?