【问题标题】:Asp.Net WebApi run MongoDB query/save asyncAsp.Net WebApi 运行 MongoDB 查询/异步保存
【发布时间】:2014-03-24 13:16:44
【问题描述】:

我目前正试图弄清楚何时使用 Task.Run 以及何时不使用。

在我的项目中,我使用 WebApi 结合 MongoDB 来存储帐户信息。

那么对于下面的示例代码,我会更好地使用来自客户端调用的 Submit 或 SumbitAsync 方法吗?

public class TestController : ApiController
{
    [HttpPost]
    public void Submit()
    {
        DoSave();
    }

    public async Task SubmitAsync()
    {
        await Task.Run(() => DoSave());
    }

    private void DoSave()
    {
        myMongoDbCollection.Save(new TestEntity());
    }
}

MongoDB C# 驱动程序目前不支持异步方法。

【问题讨论】:

    标签: c# mongodb asynchronous asp.net-web-api task


    【解决方案1】:

    在这里使用Task.Run 没有意义。

    在 ASP.NET 中使用异步 I/O 的目的是释放线程,以便它可以处理其他请求,直到 I/O 完成。同时,no 线程将被阻塞。当 I/O 操作完成时,将发出 I/O 完成端口信号,您的方法将恢复。

    使用 Task.Run,您只是将其推迟到 ThreadPool 线程,并使 线程阻塞等待 I/O。

    换句话说,如果客户端不支持异步 I/O,您的一个线程将始终阻塞。因此,您不妨同步进行所有操作,避免不必要的上下文切换。

    来自Stephen Cleary's blog post "Task.Run Etiquette Examples: Don't Use Task.Run in the Implementation"

    当您在 ASP.NET 中将 await 与 Task.Run 一起使用时,就会引入(至少)四个效率问题:

    • 额外(不必要的)线程切换到 Task.Run 线程池线程。同样,当该线程完成请求时,它必须进入请求上下文(这不是实际的线程切换,但确实有开销)。

    • 创建了额外的(不必要的)垃圾。异步编程是一种权衡:以更高的内存使用为代价获得更高的响应能力。在这种情况下,您最终会为完全不必要的异步操作创建更多垃圾。

    • Task.Run“意外”借用了一个线程池线程,导致 ASP.NET 线程池启发式算法失效。我在这里没有太多经验,但我的直觉告诉我,如果意外任务真的很短,启发式算法应该会恢复得很好,如果意外任务持续超过两秒,则不会优雅地处理它。

    • ASP.NET 无法提前终止请求,即,如果客户端断开连接或请求超时。在同步情况下,ASP.NET 知道请求线程并且可以中止它。在异步情况下,ASP.NET 不知道辅助线程池线程是“为”该请求的。可以通过使用取消令牌来解决此问题,但这超出了本博文的范围。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-30
      • 2016-06-25
      • 1970-01-01
      • 1970-01-01
      • 2017-10-01
      • 2015-02-10
      • 1970-01-01
      • 2011-12-03
      相关资源
      最近更新 更多