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

C# 将cpu绑定/io绑定的长时间运行代码包装到(异步)任务中,c#,multithreading,asynchronous,task-parallel-library,msmq,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

考虑简单的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
在内部执行以下操作:

  • 它将请求发送到专用MSMQ队列(我们称之为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>()
        );
    }
    
    使用(var requestMessage=new Message()){
    requestMessage.Body=documentStamp;
    requestMessage.Recoverable=true;
    requestMessage.Label=“request”;
    requestMessage.ResponseQueue=this.requestedDocumentsResponseQueue;
    requestMessage.Formatter=newXMLMessageFormatter(新类型[]{typeof(String)});
    //发送请求
    this.requestedDocumentsQueue.Send(requestMessage);
    //同步等待响应
    var responseMessage=this.requestedDocumentsResponseQueue.Receive();
    if(responseMessage.Label.EndsWith(“成功”)){
    返回新文档RequestResult(
    成功:没错,
    匹配:parseMatchesList(responseMessage)
    );
    }
    返回新文档RequestResult(
    成功:错,
    匹配项:Enumerable.Empty()
    );
    }
    
  • 该消息的使用者(Windows服务)进行特定的api调用。我所说的“特定”是指我们使用第三方手段来实现这一点。此调用是同步的,并且相当长。当处理结束时,使用者向请求消息的响应队列发送响应消息

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

    据我所知,运行任务使用并行化。而使用async-await对会使正在运行的任务异步。如果多个任务并行运行,可能会有所帮助

    在我的情况下,是否合理/可能合并任务处理/异步?如果是,那么从哪里开始?

    网络调用的“异步”对调用方是透明的。调用方不在乎实现是同步的还是异步的。换句话说,从客户机的角度来看,它总是异步的

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

    类似地,HTTP web服务器不关心Win32服务是同步实现还是异步实现。它只知道它将一条消息放在一个队列中,一段时间后(即异步)它从队列中获取一条响应消息

    据我所知,运行任务使用并行化。而使用async Wait对则会使正在运行的任务异步

    有点<代码>任务既可以用于异步代码,也可以用于并行代码,这一事实造成了很多混乱。然而,任务并行库结构,如
    Parallel
    和PLINQ,在并行(非异步)世界中是稳固的

    如果多个任务并行运行,可能会有所帮助

    我认为“同时”在这里是恰当的术语

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

    然后,您可以通过单个控制器操作同时调用它多次,如下所示:

    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);
    }
    
    公共异步任务请求文档(字符串stamp1、字符串stamp2){
    var task1=this.DocumentsRequestService.RequestByStampAsync(stamp1);
    var task2=this.DocumentsRequestService.RequestByStampAsync(stamp2);
    var documents=wait Task.WhenAll(task1,task2);
    返回新的JsonResult(文档);
    }
    
    网络调用的“异步”对调用方是透明的。调用方不在乎实现是同步的还是异步的。换句话说,从客户机的角度来看,它总是异步的

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

    类似地,HTTP web服务器不关心Win32服务是同步实现还是异步实现。它只知道它将一条消息放在一个队列中,一段时间后(即异步)它从队列中获取一条响应消息

    据我所知,运行任务使用并行化。而使用async Wait对则会使正在运行的任务异步

    有点<代码>任务既可以用于异步代码,也可以用于并行代码,这一事实造成了很多混乱。然而,任务并行库结构,如
    Parallel
    和PLINQ,在并行(非异步)世界中是稳固的

    如果多个任务并行运行,可能会有所帮助

    我认为“同时”在这里是恰当的术语

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

    然后,您可以通过单个控制器操作同时调用它多次,如下所示:

    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);
    }
    
    公共异步任务请求文档(字符串