本文介绍了避免使用HttpClient死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 HttpClient 并避免死锁的最佳方法是什么?我正在使用下面的代码,这些代码完全是从同步方法中调用的,但是我担心它可能导致死锁.

What is the best way to use HttpClient and avoid deadlock? I am using the code below, called entirely from synchronous methods, but I concerned it maybe causing a deadlock.

我已经阅读了诸如 .ConfigureAwait(false) .GetAwaiter() .GetResult()之类的函数,但我正在寻求有关最佳做法方法的意见.

I've done some reading on functions like .ConfigureAwait(false), .GetAwaiter(), .GetResult() but I am looking for input on the best practice approach.

不太精确的代码,但是足够接近.

Not quite exact code, but close enough.

public static bool TryRequest(string url, out response)
{
    HttpContent content = new StringContent(json, Encoding.UTF8, "application/json");
    using (HttpClient client = new HttpClient())
    {
       HttpResponseMessage responseMessage = null;

       switch (verb)
       {
          case HttpVerb.Put:
             responseMessage = client.PutAsync(url, content).Result;
             break;
          case HttpVerb.Post:
             responseMessage = client.PostAsync(url, content).Result;
             break;
          case HttpVerb.Delete:
             responseMessage = client.DeleteAsync(url).Result;
             break;
          case HttpVerb.Get:
             responseMessage =  client.GetAsync(url).Result;
             break;
       }

       if (responseMessage.IsSuccessStatusCode)
       {
          responseContent = responseMessage.Content.ReadAsStringAsync().Result;
          statusCode = responseMessage.StatusCode;
       }
    }
}

推荐答案

您似乎正在尝试同步运行异步代码.

It looks like you are trying to run asynchronous code synchronously.

使用WinForms和WPF,您无法安全地做到这一点!

With WinForms and WPF YOU CANNOT SAFELY DO THIS!

您唯一可以做的就是一直使用异步..net异步存在的一个已知问题.您可以使用 public异步void XXX()方法.但是您不知道它们什么时候完成.与事件处理程序结合使用时,您仅应使用 async void .

The only thing you can do is to use async all the way up. Its a known problem with .net async. You can use public async void XXX() methods. But then you don't know when they complete. You should ONLY ever use async void when coupled with an event handler.

陷入僵局的原因是默认的 TaskFactory 将尝试将Interupt回调封送回 SynchronizationContext ,这很可能是您的UI线程.

The reason you are getting deadlocks is that the default TaskFactory will try to marshal interupt callbacks back to the SynchronizationContext, which is likely your UI thread.

即使您使用 Task.ConfigureAwait(false),也无法保证在调用堆栈的更深处,您不会有需要UI线程的回调.

Even if you use Task.ConfigureAwait(false) there is no guarantee that further down the callstack you don't have a callback which expects the UI thread.

只要您阻止 SynchronizationContext 线程,就极有可能导致死锁.

As long as you block the SynchronizationContext thread, there is a very high possibility that you will deadlock.

还值得注意的是,异步代码有时似乎可以工作.这是因为,允许返回 Task 的异步方法同步完成(例如, Task.Return< T>(T结果)).具有缓存的方法(例如HttpRequests)通常会发生这种情况.

It is also worth noting that it is possible that the asynchronous code seems to sometimes work. This is because, an async method that returns a Task, is allowed to synchronously complete (for example Task.Return<T>(T result)). This will often happen with methods that have a cache (like HttpRequests).

@SriramSakthivel建议您可以通过将异步方法包装在 Task.Run 中来同步运行异步方法.这是因为 Task.Run 将在没有父 SynchronizationContext 的情况下运行代码.

@SriramSakthivel suggest that you can run an async method synchronously by wrapping it within Task.Run. This is because Task.Run will run the code without the parent SynchronizationContext.

Task.Run(RunRequest).Result;

我个人不建议这样做,因为它依赖于 Task.Run 的特定实现以及 TaskFactory 来起作用.新版本的.net完全有可能(但不太可能)破坏这段代码.

I personally do not recommend this, as it relies on the specific implementation of Task.Run along with TaskFactory to work. It is entirely possible (but unlikely) that a new version of .net will break this piece of code.

这篇关于避免使用HttpClient死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-07 03:59