httpclient async/await 与否

Posted

技术标签:

【中文标题】httpclient async/await 与否【英文标题】:httpclient async/await or not 【发布时间】:2013-12-03 19:14:06 【问题描述】:

我正在使用一个 httpclient 实例向 rest web api 发送多个请求以获取数据。这是我的代码的样子:

首先我有一个控制层,它为数据调用数据层。

public class ControlLayer

    protected DataLayer dal;

    //constructors here

    public int getInfo1(int param)
    
      int ret = this.dal.getInfo1(param);
      return ret;
    

    public int getInfo2(int param)
    
      int ret = this.dal.getInfo2(param);
      return ret;
    

然后我有调用 webAPI 的 dataLayer,它看起来像这样。这里为简单起见,我直接使用 .result。

public class DataLayer

    HttpClient client = new HttpClient();
    string url = "";

    public int getInfo1(int param1)
    
      int ret=0;
      HttpResponseMessage response = client.GetAsync(url).Result;
      //.... do some work, get the value for ret

      return ret;
    

    public int getInfo2(int param1)
    
      int ret = 0;
      HttpResponseMessage response = client.GetAsync(url).Result;
      //.... do some work, get the value for ret

      return ret;
    

我的问题是,我看到一些教程说我们应该避免使用 .result,因为它可能会导致死锁。我不确定在我的情况下是否需要使用 异步/等待?如果我确实需要,我知道我应该一直异步,但我确实希望我的 controlLayer 是同步的,因为我有其他层调用 controlLayer 的函数,我不希望所有 layer 的函数都是异步的,结果是 Task,这是一种同步而不是异步的情况吗?我想念吗 某物?任何建议表示赞赏。谢谢!

【问题讨论】:

如果您不希望代码异步(是好是坏 - 您的个人电话),那么不要进行异步调用。不知道你有什么问题...... 感谢您的快速回复,您是否建议直接使用 .result 函数?这会导致僵局吗? @AlexeiLevenkov HttpClient 有一个异步 API,因此您必须使用 Resultawait 结果。 HttpClient 不是那里唯一的 API...如果有人更喜欢同步代码 WebRequest 可能是另一种选择...但这完全取决于作者是否可以控制代码的使用位置(请参阅 sinelaw 的答案 +1 中的链接 - 如果是控制台应用程序同步等待异步方法是可以的,否则必须注意避免死锁。 @AlexeiLevenkov HttpClient 可能不是唯一的选择,但我仍然觉得它足够好,我不想想使用其他人。我如何让 HttpClient就像 像 WebClient 一样工作(同步),没有死锁的风险? (不过,我仍然想阻塞 UI 线程,直到请求完成)。 【参考方案1】:

我确实希望我的 controlLayer 是同步的,因为我有其他层调用 controlLayer 的函数,我不希望所有层的函数都是异步的,结果是 Task

我建议您重新考虑这一点。 Web 请求本质上是一种异步操作,因此我建议您将“控制层”公开为异步 API,并允许 async 通过代码库中的层“增长”。

但是,如果您真的想要一个同步 API,那么您应该只调用同步 API。例如,使用WebClient 而不是HttpClient不要调用 Result 来用同步 API 包装异步 API。

【讨论】:

@LenielMacaferi:我不同意这个答案。在某些平台上,在 HttpClient 异步 API 上调用 Result 会导致死锁。 @StephenCleary 所以,如果 Result 可能导致死锁,我怎样才能在没有死锁风险的情况下使用 HttpClient?我希望这一切都是同步的,就像 WebClient 的工作方式一样,同时仍然使用新的、更高级的 HttpClient。 @Dexter: HttpClient 是异步的。 WebClient 支持同步和异步代码。 @StephenCleary 以及 WebClient 在同步模式下究竟是如何工作的? “Web 请求本质上是一个异步操作”,所以 WebClient 中的同步函数可能有一些等待的代码。而且我怀疑使用 WebClient 的同步方法可能会产生死锁(微软可能足够聪明)。那么,我自己如何使用 HttpClient 来做到这一点? @Dexter: WebClient 在其同步调用中阻塞。您可以调用HttpClient 的异步方法,然后在返回的任务上调用GetAwaiter().GetResult()但是, 在某些平台上,这会因为HttpClient 的实现而陷入僵局。它根本不是为这种情况而设计的。【参考方案2】:

如果您的代码是异步的,您只需要使用asyncawait - 例如,如果它同时分派多个请求,在发送请求后执行工作,而不是阻塞直到响应到达。

暂时忽略死锁问题 - 如果您的代码只是同步的,即:每次发送请求时,您只需等待响应,然后再执行其他操作,您不需要使用 await 并且可以使用Result。请参阅this question 进行类似的辩论。或者,您可以使用同步 API(如 cmets 和其他答案中建议的 WebClient)。

至于Result 相关的死锁,我建议您阅读this article on MSDN 以更好地了解发生了什么以及为什么。如果你正在编写一个简单的控制台应用程序,你真的不需要担心它(处理它的正确方法是只让你的 Main 方法非异步,并在那里使用 ResultWait) .

【讨论】:

谢谢!就我而言,我有一个 clientLayer 发送请求参数,可以同时发送,在我得到响应后,我会将结果发送到 clientLayer,所以我认为我确实需要异步和等待,但你知道如何处理异步的同步? @Vicky,阅读这篇文章——他们推荐的“最佳实践”之一是“一直异步”——让你的所有代码一直异步到可能的***别,并使用 Result和 Wait() 那里。

以上是关于httpclient async/await 与否的主要内容,如果未能解决你的问题,请参考以下文章

使用async await使用Web请求进行超时处理

任务(异步,等待):我需要输入这些都是连接层还是仅具有 ASYNC 调用的层,即 HttpClient.GetAsync?

HttpClient SendAsync 阻塞主线程

如何正确设置 HttpClient 的延续?

在同步类库中使用HttpClient

在 HttpClient 异常上显示 AlertDialog (Xamarin Android)