首页 > 解决方案 > 后台启动的任务在第一次遇到等待后未完成/终止

问题描述

在 ASP.NET 应用程序中,我有一个动作,当它被点击时,会以下列方式启动一个新的后台任务:

Task.Factory.StartNew(async () => await somethingWithCpuAndIo(input), CancellationToken.None, TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning, TaskScheduler.FromCurrentSynchronizationContext());

我不是在等待它,我只是想让它开始,并继续在后台工作。之后,我立即向客户返回响应。

但是由于某种原因,在执行后台工作的初始线程遇到等待方法完成的 await 之后,在调试时,我成功地解决了该方法,但是在返回时,执行只是停止并且不会在该点以下继续。

有趣的是,如果我完全等待这个任务(使用 double await),一切都会按预期进行。

这是由于 SynchronizationContext 造成的吗?在我返回响应的那一刻,同步上下文被释放/删除?(方法内部使用了 SynchronizationContext)

如果是由于这个原因,问题到底发生在哪里?

A) 当调度器试图在给定的同步上下文上分配工作时,它已经被释放了,所以什么都不会提供

B)在执行方法的某个地方,当我向客户端返回响应时,同步上下文丢失,不管其他任何事情。

C) 完全不同的东西?

如果是 A),我应该能够通过Thread.Sleep()在安排工作和返回响应之间简单地解决这个问题。(试过了,没用。)

如果是 B) 我不知道如何解决这个问题。帮助将不胜感激。

标签: c#asp.netmultithreadingasynchronousasync-await

解决方案


正如加布里埃尔·卢西(Gabriel Luci)所指出的,这是由于第一个等待不完整的Task立即返回,但还有一个更广泛的观点需要说明Task.Factory.StartNew

Task.Factory.StartNew不应与async代码一起使用,也不应与TaskCreationOptions.LongRunning. TaskCreationOptions.LongRunning应该用于调度长时间运行的CPU 密集型工作。使用一个async方法,它在逻辑上可能是长时间运行的,但Task.Factory.StartNew它是关于启动同步工作的,异步方法的同步部分是第一个之前的位await,这通常很短。

以下是 David Fowler(微软 ASP.NET 团队的合作伙伴软件架构师)对此事的指导: https ://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/86b502e88c752e42f68229afb9f1ac58b9d1fef7/AsyncGuidance.md#avoid-using-taskrun-长时间运行的工作阻塞线程

见第三个灯泡:

不要将 TaskCreationOptions.LongRunning 与异步代码一起使用,因为这将创建一个新线程,该线程将在第一次等待后被销毁。


推荐阅读