【问题标题】:Parallel Invoke with AwaitAsync in WebApi blocking在 Web Api 阻塞中使用 Await Async 并行调用
【发布时间】:2015-07-27 16:40:43
【问题描述】:

我有一个 webApi 操作,它在 || 中执行 2 个操作它在内部调用 HttpClient sendAsync。如果我应用调试器并执行调用,它会工作并返回。如果我删除调试器,两个异步调用仍然有效(在 Fiddler 中检查)但 WebApi 操作的调用者没有得到任何响应(使用 AdvanceRest chrome 插件)。从其他线程来看,可能我没有正确使用 async/await 并且与 ASP.NET 同步上下文相关

//**WEB API Controller***
class SomeController 
{
     public HttpResponseMessage Get()
     {
         Client someClient = new Client();
         aResponse = new aResponse();
         bResponse = new bResponse();
         Parallel.Invoke(
         () => {aResponse = someClient.a()},
         () => {bResponse = someClient.b()});

        var response = {a=aResponse, b=bResponse};
        return Response.Create(OK, response}
     }

class SomeClient
{
    AResponse a()
    {
        var clientResponse = ClientMgr.Execute("url");  
        return new AResponse {HttpClientResponse = clientResponse.Result}
    }

    BResponse b()
    {
        var clientResponse = ClientMgr.Execute("url");  
        return new BResponse {HttpClientResponse = clientResponse.Result}
    }
}

//Utility CLASS
public class ClientMgr
{
    public static async Task<HttpResponseMessage> Execute(string url)
    {
        request = new HttpRequestMessage();
        //....request fill
        HttpClient client = new HttpClient();
        var response = await client.SendAsync(request);
        client.dispose();
        return response;
    }
}

public class AResponse 
{
    HttpResponseMessage HttpClientResponse {get;set;}
    // Some other properties....
}

为什么在我使用断点时操作会返回响应,但当我删除它们时,它不会返回响应?

【问题讨论】:

  • 什么是Execute?您的客户管理器中只有一个 ExecuteFeed 方法。
  • 对不起..是一个错字...它只执行。
  • 您不会在任何地方 awaiting 执行 Execute 的响应。 Invoke开始异步操作并立即完成。无论如何,您可以使用var results=await Task.WhenAll(someClient.a(),someClient.b(),...); 而不是Parallel.Invoke。顺便说一句,代码不会编译。 Execute 返回一个任务,而 a 返回一个 HttpResponseMessage。我假设a() 实际上也返回了Task&lt;HttpResponseMessage&gt;
  • a() 和 b() 返回带有一些属性/数据的自定义响应,这些属性/数据是 ExecuteFeed 结果的一部分。
  • 那为什么a()b()返回HttpResponseMessage?请将您的代码示例修复为实际工作示例。

标签: c# async-await


【解决方案1】:

您的问题(除了您发布的代码无法编译) 是在您调试时,异步操作实际上完成了。当您不调试时,它们不会,它返回一个Task&lt;YourResponse&gt;,而不是Task 的实际结果。

为了使其工作,将您的方法标记为 async 并使用 Task.WhenAll 异步等待两个任务:

[HttpGet]
public async Task<HttpResponseMessage> GetAsync()
{
    Client someClient = new Client();
    var aTask = someClient.AAsync();
    var bTask = someClient.BAsync();

    await Task.WhenAll(aTask, bTask);
    var response = { a = aTask.Result, b = bTask.Result };
    return Response.Create(OK, response}
}

旁注 - 当您有 IO 绑定操作时,您不需要使用 Paralle.Invoke。这些是冗余线程,将被阻塞等待 IO 完成。

【讨论】:

  • 谢谢.. 我会尝试并将其标记为答案。但是,这是否意味着在这种情况下 Parallel.Invoke 不能使用?同样在返回响应之前的函数 a() 和 be() 中,我做了 clientResponse.Await() 但这也没有解决问题(我认为这可以确保任务完成)......代码没有像我一样编译前面提到它是伪的:)
  • @helloworld 当您在 SO 上发布问题时,它应该是 MCVE,而不是伪代码。您可以使用Parallel.Invoke,但这里没有理由这样做。您需要在调用堆栈的顶部使用await,在a()b() 中使用await 是不够的。
  • 我的意思是 wait() 不在 a() 和 b() 内等待。文档说 Wait() 确保任务等到完成。所以我期待即使 a() 和b() 不是异步的(因为我不希望它们是异步的),仍然通过在返回从 Execute() 收到的任务的响应之前强制完成调用 Wait(),它们将确保任务执行并且我可以使用 Parallel调用以执行多个此类操作..
  • 不要将Wait() 与异步代码一起使用。它会导致你陷入僵局。
猜你喜欢
  • 1970-01-01
  • 2021-11-18
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-03
  • 1970-01-01
相关资源
最近更新 更多