将cpu绑定/ io绑定的长时间运行代码包装到(异步)任务中

时间:2015-12-15 14:25:48

标签: c# multithreading asynchronous task-parallel-library msmq

考虑简单的MVC5控制器:

public class DocumentsController {

    // ctor code is omitted

    [HttpPost, Route("api/documents/request/stamp={stamp}")]
    public ActionResult RequestDocuments(string stamp) {

        var documents = this.DocumentsRequestService.RequestByStamp(stamp);
        return new JsonResult(documents);
    }
}

DocumentsRequestService在内部完成这些事情:

  1. 它向专用的 MSMQ-queue 发送请求(让我们称之为 M )并且同步等待传入的消息在 M 的响应队列中:

    using(var requestMessage = new Message()) {
    
        requestMessage.Body = documentStamp;
        requestMessage.Recoverable = true;
        requestMessage.Label = "request";
        requestMessage.ResponseQueue = this.requestedDocumentsResponseQueue;
        requestMessage.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });
    
        // send request
    
        this.requestedDocumentsQueue.Send(requestMessage);
    
        // synchronously wait for response
    
        var responseMessage = this.requestedDocumentsResponseQueue.Receive();
    
        if(responseMessage.Label.EndsWith("success")) {
            return new DocumentsRequestResult(
                success: true,
                matches: parseMatchesList(responseMessage)
            );
        }
    
        return new DocumentsRequestResult(
            success: false,
            matches: Enumerable.Empty<DocumentsRequestMatch>()
        );
    }
    
  2. 该邮件的使用者( Windows服务)进行特定的api调用。通过说'具体',我的意思是我们使用第三方手段来做到这一点。这个调用是同步的,而且很长。当处理结束时,消费者向请求消息的响应队列发送响应消息。

  3. 当响应到达 M 的响应队列时,是时候解析并将结果返回给控制器。
  4. 从最终用户的角度来看,这个任务应该是阻塞的,或者至少应该看起来像阻塞。

    据我所知,运行任务会使用并行化。而使用异步 - 等待对使运行任务异步。如果几个任务并行运行可能会有所帮助。

    在我的案例中合并/可能与任务 / 异步合并?如果是,那么我从哪里开始呢?

1 个答案:

答案 0 :(得分:4)

&#34;异步&#34;网络呼叫对呼叫者是透明的。对于调用者来说,实现是同步还是异步并不重要。换句话说,从客户的角度来看,它总是异步

例如,如果RequestDocuments是同步的或异步的,HTTP客户端就不会关心;无论哪种方式,HTTP客户端都会发送请求并在一段时间后(即异步)接收响应。

同样,HTTP Web服务器并不关心Win32服务是同步实现还是异步实现。它只知道它将消息放入队列中,并且稍后(即异步地)它从队列中获取响应消息。

  

据我所知,运行Task会使用并行化。而使用async-await对使运行任务异步。

排序。 Task可用于异步或并行代码,这一事实引起了很多混乱。但是,Parallel和PLINQ等任务并行库构造牢牢地处于并行(非异步)世界。

  

如果几个任务并行运行可能会有所帮助。

我相信&#34;同时&#34;这是适当的术语。

首先,请注意ASP.NET免费为您提供了大量的并发性。如果您想在内部并发每个请求,那么您可以通过Task.WhenAll相当容易地完成此操作。例如,您可以将DocumentsRequestService调用更改为异步(假设您的消息队列API支持异步调用):

using(var requestMessage = new Message()) {
  ...

  // send request
  await this.requestedDocumentsQueue.SendAsync(requestMessage);

  // asynchronously wait for response
  var responseMessage = await this.requestedDocumentsResponseQueue.ReceiveAsync();

  ...
}

然后你可以从一个控制器动作同时多次调用它:

public async Task<ActionResult> RequestDocuments(string stamp1, string stamp2) {
  var task1 = this.DocumentsRequestService.RequestByStampAsync(stamp1);
  var task2 = this.DocumentsRequestService.RequestByStampAsync(stamp2);
  var documents = await Task.WhenAll(task1, task2);
  return new JsonResult(documents);
}