HostingEnvironment.QueueBackgroundWorkItem真的会延迟回收吗?

Does HostingEnvironment.QueueBackgroundWorkItem really delay recycling?

我读过 this documentation 上面说 运行ning 与 HostingEnvironment.QueueBackgroundWorkItem:

的动作

Differs from a normal ThreadPool work item in that ASP.NET can keep track of how many work items registered through this API are currently running, and the ASP.NET runtime will try to delay AppDomain shutdown until these work items have finished executing. This API cannot be called outside of an ASP.NET-managed AppDomain. The provided CancellationToken will be signaled when the application is shutting down.

所以我写了这个示例代码:

private void Check() {   
  HostingEnvironment.QueueBackgroundWorkItem(ct => CheckRecyclingBehaviour(ct));}
}

private async void CheckRecyclingBehaviour(CancellationToken ct) {
  while (true) {
    await Task.Delay(1000);
    if (ct.IsCancellationRequested) {
      AppendToFile("Recycling soon...");
      await Task.Delay(1000);
      AppendToFile("But we still have time to finish...");
      break;
    }
  }
}

我已经 运行 check()(在 IIS 7 上),过了一会儿我通过 IIS 管理器强制回收。

最后,我检查了 debug.txt 文件,其中包含一行:"Recycling soon...".

所以我猜 CancellationToken 已发出信号,但 AppDomain 关闭并没有真正延迟(因为第二次打印从未发生)。

这看起来很奇怪,尤其是考虑到我读过的几篇文章说 recycling will be delayed by 30 seconds.

我是不是漏掉了什么?

您正在使用 async void,这就是您的问题。正如我在 my MSDN article on async best practices, you should avoid async void.

中描述的那样

async void 更改为正确的 async Task,您可能会看到它正常工作。

更多信息:检测 async void 方法的完成并非易事,因此您发布到 QueueBackgroundWorkItem 的代码实际上几乎立即完成(在第一个 await 处) .当 ASP.NET 关闭时,它设置取消标记(将第一行同步写入文件),然后等待任何排队的工作。由于工作已经完成,它只是立即拆除应用程序域,放弃该方法的其余部分。

如果您使用 async Task 方法,那么 QueueBackgroundWorkItem 将理解代码在任务完成之前未完成。