【问题标题】:Task.WaitAll() aborted inside a Task.Run()Task.WaitAll() 在 Task.Run() 中中止
【发布时间】:2018-10-17 12:40:36
【问题描述】:

我有一个 web api 2 控制器,客户端向控制器请求某种 html 生成(包括图像、文件等)。由于这个过程需要一些时间,我不希望用户等待,我在控制器中遵循了以下方法:

...Controller(){
Task.Run(() =>
        {
          //calling heavy duty method to download files where Task.WaitAll() resides
          DownloadAndRename()
        });
}

DownloadAndRename(){
     //created some child task here and run them in task.waitall()
     //Task.WaitAll() here
}

我为每个文件创建了下载、重命名和其他过程的任务。然后在 Task.WaitAll() 中执行它们。

当我在本地运行应用程序时,一切正常。但是当我部署到我的测试服务器时,它抛出了以下异常:

Message: System.Threading.ThreadAbortException: Thread was being aborted.

附:在我的电脑中,我只有一个应用程序在应用程序池中运行,而在我的测试服务器中,该特定池中有 8 个。

如何克服异常?

更新 1:我尝试删除 task.WaitAll 并在不使用 Task 的情况下执行实施。不过,我得到线程中止错误,我认为 Task.Run() 以某种方式超时。

【问题讨论】:

  • 您可以查看其他选项,例如 Hangfire。它旨在在 asp.net framework / asp.net core 中执行长时间运行的进程。
  • 如果你想异步运行DownloadAndRename(),你可以把Task.Run()返回的Task传给Task.WaitAll()。 Task.WaitAll() 需要在 Controller() 范围内调用。但是请注意,Task.WaitAll() 将阻塞调用线程。是否可以使 Controller 方法异步并等待 DownloadAndRename() 代替?这将确保调用线程不会被阻塞。
  • @JamieButterworth,我已尝试删除 task.WaitAll,并在不使用 Task 的情况下执行实施。我仍然收到线程中止错误,我认为 Task.Run() 以某种方式超时。
  • 问题是,asp.net 并没有“意识到”你正在处理的任务以及它围绕回收等的一些机制,只是试图保护 requests以及与之相关的事物。看起来这确实会更好地放置在一个单独的可执行文件中,例如 Windows 服务,然后 asp.net 应用程序通过某种形式的 IPC 与之交互。
  • 这段代码保证了 ThreadAbortException。 Task.Run 不等待就开始了一项任务,然后就忘记了它。 Task.WaitAll() 确保当 ASP.NET 在请求结束或回收时终止线程时,此任务仍然存在。有 LOT 的文章解释了如何在 ASP.NET 或 ASP.NET Core 中启动长时间运行的作业。你的目标是哪一个?

标签: c# asynchronous asp.net-web-api2


【解决方案1】:

我认为这个问题是对任务执行的简单误解。

如果您希望任务立即作为后台任务运行,您可以将 async 关键字和 Task 返回类型添加到 Controller 操作,并使 DownloadAndRename() 异步并使其返回一个 Task,然后从内部等待 DownloadAndRename()控制器动作范围。这样调用线程不会被阻塞,任务之后的任何代码都不会被执行,直到返回的任务完成。

async Task Controller()
{
await DownloadAndRename();
}

如果删除后仍然不起作用 Task.WaitAll(),我会读一下它,因为它可能真的是 如您所说超时或可能由于其他原因而异常: Why am i getting "Thread was being aborted" in asp.net?

【讨论】:

  • 我已经遵循了第二个选项,但它失败了。我想知道为什么它可以在我的本地机器上工作,但不能在我的开发服务器上工作。
  • 第二个选项是没有意义的,根本不起作用 - IIS 将在某个时候终止该线程,除非操作恰好及时完成。这也是没有意义的——当当前线程可以自己执行操作时,为什么要启动 another 线程? Web 应用程序中的async/await 用于提高可伸缩性,而不是避免阻塞。没有要阻止的 UI 线程,所有请求都由不同的线程提供服务
  • @PanagiotisKanavos 谢谢。我已通读 Phil Haack 的文章,现在了解像示例 2 那样运行任务的危险,因此我已将其从答案中删除。
  • @PanagiotisKanavos,在完成 DownloadAndRename 方法后,我有一些操作要在控制器中完成,使我的控制器异步阻塞了我的 UI 线程。我不确定出了什么问题。也许我需要对此进行更多研究。
  • @lukai Web 应用程序中没有 UI 线程。使控制器async 不会阻止任何东西。如果您希望您的操作完成但让作业在后台运行,您有一个后台任务。您需要使用QueueBackgroundWorkItem 告诉 IIS,而不是中止线程
猜你喜欢
  • 2020-09-16
  • 2021-11-08
  • 1970-01-01
  • 2017-08-21
  • 1970-01-01
  • 2019-09-07
  • 1970-01-01
  • 1970-01-01
  • 2017-12-07
相关资源
最近更新 更多