C# 使用WebApi执行I/O繁重异步任务的最佳实践

C# 使用WebApi执行I/O繁重异步任务的最佳实践,c#,asp.net-web-api,async-await,C#,Asp.net Web Api,Async Await,我有一个异步操作通过WebAPI 1.0响应HTTP POST。收到此请求时,我需要做两件事: 执行数据库插入,并将该新条目的标识返回到调用该函数的WebApp 使用这个身份做一大堆I/O繁重的工作,这些工作是WebApp和用户不会立即关心的 在一个完美的世界里,我会把数据放在某个队列的某个地方,然后让一个小工人来处理队列。既然我不能立即这样做,那么什么是确保这项工作在不影响用户的情况下完成的最好方法呢 [HttpPost] public async Task<int> Post([

我有一个异步操作通过WebAPI 1.0响应HTTP POST。收到此请求时,我需要做两件事:

  • 执行数据库插入,并将该新条目的标识返回到调用该函数的WebApp
  • 使用这个身份做一大堆I/O繁重的工作,这些工作是WebApp和用户不会立即关心的
  • 在一个完美的世界里,我会把数据放在某个队列的某个地方,然后让一个小工人来处理队列。既然我不能立即这样做,那么什么是确保这项工作在不影响用户的情况下完成的最好方法呢

    [HttpPost]
    public async Task<int> Post([FromBody]Object myObject)
    {
        return await new ObjectLogic().InsertObject(myObject);
    }
    public async Task<int> InsertObject(Object myObject)
    {
        var id = await new ObjectData().InsertObjectRoot(myObject);
        Task.Run(() =>  new ObjectData().ObjectWork(id, myObject));
        return id;
    }
    
    [HttpPost]
    公共异步任务发布([FromBody]对象myObject)
    {
    返回wait wait new ObjectLogic().InsertObject(myObject);
    }
    公共异步任务插入对象(对象myObject)
    {
    var id=wait new ObjectData().InsertObjectRoot(myObject);
    运行(()=>newObjectData().ObjectWork(id,myObject));
    返回id;
    }
    
    这是我提出的解决方案,但我认为必须有更好的解决方案,因为我基本上是从线程池中窃取线程,直到我的工作完成。有更好的办法吗?我想我可以在InsertObject方法中使用ConfigureAwait(false),因为我真的不关心那里的上下文

    // await async function but use ConfigureAwait
    public async Task<int> InsertObject(Object myObject)
    {
        var id = await new ObjectData().InsertObjectRoot(myObject);
        await new ObjectData().ObjectWork(id, myObject).ConfigureAwait(false);
        return id;
    }
    
    //等待异步函数,但使用ConfigureAwait
    公共异步任务插入对象(对象myObject)
    {
    var id=wait new ObjectData().InsertObjectRoot(myObject);
    等待新的ObjectData().ObjectWork(id,myObject).ConfigureAwait(false);
    返回id;
    }
    
    一个问题是,您的Web API是否应该除了

    • 收到请求
    • 把它放在队列上
    • 使用
      id
      响应以指示已收到请求
    这在某种程度上取决于你期望或可能看到的负载类型。但是如果您从一开始就担心可用线程的数量,那么答案可能是您的Web API只执行上述步骤

    队列可以是文字队列,如MSMQ(或现在流行的任何队列),也可以由插入表中的记录组成。然后,一个单独的Windows服务可以处理该队列并执行I/O繁重的工作。它甚至不必在同一台服务器上。您可以单独缩放它

    如果用户确实想要一些最终指示,那么他们可以使用您返回的
    id
    每隔一段时间进行轮询。但对我来说,关键在于这句话:

    使用该身份进行大量I/O繁重的工作,这是Web应用程序和用户不会立即关心的。


    web应用程序的工作是提供响应,即用户真正关心的事情。如果它是长时间运行的、用户不关心的I/O重工,那么我会考虑卸载它。

    你担心你的线程会用完吗?这是可能的。。。为什么你不能在一个单独的线程上实现你的队列想法呢?一个简单的规则就是这个任务。运行对于IO绑定的工作来说总是一个坏主意。你应该在那里做一些分析。如果遇到IO瓶颈,那么不要担心异步。如果您遇到了线程池瓶颈,那么就执行异步。实际上,您并没有窃取任何线程。有很多帖子都是关于如何实施用火遗忘的坏主意的。确保搜索…首先,感谢您的回复。我相信你是正确的使用MSMQ或类似的东西是长期的解决方案。我正在寻找一个婴儿步骤在正确的直接,因为我目前有现有的代码在生产中运行,它的工作。“HostingEnvironment.QueueBackgroundWorkItem”似乎是一个小步骤,因为它注册了任务。