c# - 后台启动的任务在第一次遇到等待后未完成/终止
问题描述
在 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) 我不知道如何解决这个问题。帮助将不胜感激。
解决方案
正如加布里埃尔·卢西(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 与异步代码一起使用,因为这将创建一个新线程,该线程将在第一次等待后被销毁。
推荐阅读
- windows - 重新枚举从旧固件升级到新固件且描述符发生变化的 USB 设备
- api-platform.com - 收集操作的额外数据
- javascript - DOM MutationObserver 的问题 - Javascript
- apache-spark - 使用 Azure 数据工厂 V1 的 Spark 作业链
- mysql - 世界地图面板格拉法纳
- excel - 如果值为 EMPTY 与 NULL,VBA TRIM 函数会返回什么?
- python - 将用户/项目视图数据转换为 2D 指标
- ruby-on-rails - 在导轨中连接两个模型
- javascript - Vue应用程序,Javascript,有条件地将对象添加到数组中
- javascript - 打破承诺地图系列