如何验证异步方法中的死锁和HttpClient.PostAsync调用? [英] How can I verify a deadlock in my async to sync method and HttpClient.PostAsync calls?

查看:374
本文介绍了如何验证异步方法中的死锁和HttpClient.PostAsync调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的程序陷入僵局,但我不知道为什么以及如何解决它.

简短版本:

asyncsync的方法锁定等待异步调用,该调用将调用另一个,依此类推,直到HttpClient.PostAsync调用. http调用永远不会发生,至少它不会到达服务器(我也拥有).客户端中没有错误.我的主要问题在本SO问题的末尾.谢谢!

长版:

我知道提出死锁非常容易,我们必须小心.我试图遵循以下建议:1.将异步传播到所有方法,然后2.尽可能使用ConfigureAwait(false). (我认为主要的提倡者是Stephen Cleary,因为他的博客和许多SO的答案,我已经阅读了很多).

嗯,我的程序... 不幸的是,我无法在此处发布完整的示例代码,因为它很长.我将其描述为调用异步方法B的同步方法A,该方法调用另一个异步方法,该方法调用另一个异步方法,依此类推. 最终,最后一个异步调用是HttpClient.PostAsync.

await HttpClient.PostAsync处停止程序.另外,Http帖子永远不会触发(我拥有目标服务器,在这种情况下,它永远不会收到请求). (我仔细检查了uri等.)

因此,同步方法将锁定,以等待B的异步任务完成,而该任务永远不会发生. A看起来像这样:

public Byte[] A()
{
var task = BAsync();
return task.GetAwaiter().GetResult();
}

我以这种方式使用同步,因为他的方法不需要上下文,并且我看到Stephen在Nito中建议的方法是使用此方法实现的. (我也尝试使用task.Result来获得相同的结果).

http帖子调用的代码为:

private static async Task<HttpResponseMessage> PostAsync(Uri serverUri, HttpContent httpContent)
{
var client = new HttpClient();
return await client.PostAsync(serverUri, httpContent).ConfigureAwait(false);
}

应用程序的UI冻结.这是WP8应用程序.在这方面,按钮不响应Click事件,但ScrollViews仍然有效.这是另一个问题的主题,但我更希望在问题中包含此详细信息.

我什至不确定自己是否有死锁,或者是HttpClient错误? (我不这么认为,相同的方法正在同一应用程序的其他工作流程中工作).

我试图验证是否存在死锁,并使用了VS的线程调试器窗口,但似乎只有主线程处于活动状态.我还尝试了所有其他类型的调试器窗口,但没有任何提示.

我的主要问题是:

  1. 我陷入僵局了吗?
  2. 如何使用VS验证是否确实存在死锁?
  3. Client.PostAsync吗?如果是,为什么以及如何解决?
  4. 如果没有,请提出任何想法.


使用MethodInfo.Invoke的反射调用方法A.我相信现在这是问题的一部分.

解决方案

我相信您会遇到僵局,尽管我不确定如何证明这一点.

大多数平台上的

HttpClient在内部正确使用ConfigureAwait(false),但在少数平台上则没有.我相信WP8就是其中之一.这意味着您可以正确使用ConfigureAwait(false)的所有内容,但HttpClient仍可能导致死锁.

最好的解决方案是始终保持异步状态.但是,如果那不可能,那么我想到了两种选择:

  1. HttpClient工作推到后台线程.

    public Byte[] A()
    {
      var task = Task.Run(() => BAsync());
      return task.GetAwaiter().GetResult();
    }
    

  2. 在前台线程上建立一个嵌套循环,以执行任何异步工作.

    public Byte[] A()
    {
      return AsyncContext.Run(() => BAsync());
    }
    

    请注意,AsyncContext来自我的 AsyncEx库.我相信 AsyncContext应该可以在WP8上使用,但实际上并没有在该平台上使用它.

I'm having a deadlock in my program but I can't figure out why and how to fix it.

Short version:

An async to sync method locks waiting for an async call, which calls another, and so on until a HttpClient.PostAsync call. The http post call never happens, at least it doesn't arrives in the server (which I own too). No errors in the client. My main questions are at the end of this SO question. Thanks!

Longer version:

I know that it is very easy to come up with deadlocks and we must be careful. I'm trying to adhere to the advices of 1. Propagate the async down to all the methods and 2. Use ConfigureAwait(false) whenever possible/make sense. (I think the main advocate of this is Stephen Cleary as his blog and answers in many SO which I have read many of them).

Well, my program... I cannot post a full sample code here unfortunately, it's rather long; I describe it as a sync method A that calls an async method B, which calls another async, which calls another async, etc. Eventually the last async call is HttpClient.PostAsync.

Program stop's at the await HttpClient.PostAsync. Also, the Http post never fires (I own the target server and in this case it never receives a request). (I double checked the uri etc.).

As a result, the synchronous method locks waiting for B's async task to complete which never happens. A looks like this:

public Byte[] A()
{
var task = BAsync();
return task.GetAwaiter().GetResult();
}

I use synchronization this way as he method does not need the context back, and I saw the method suggested by Stephen in Nito is implemented using this. (I also tried task.Result instead with same results).

The code of the http post call is:

private static async Task<HttpResponseMessage> PostAsync(Uri serverUri, HttpContent httpContent)
{
var client = new HttpClient();
return await client.PostAsync(serverUri, httpContent).ConfigureAwait(false);
}

The app's UI freezes. It's a WP8 app. In this aspect, the buttons do not react to Click events but ScrollViews still work. This is topic for another question but I prefer to include this detail in the question.

I'm not even sure I have a deadlock, or maybe is a HttpClient bug? (I don't think so, the same method is working in other workflows in the same app).

I tried to verify for deadlock and used VS's threads debugger window but only the main thread seems to be active. I also tried with all other sort of debugger windows but nothing gave me a hint.

My main questions are:

  1. Am I having a deadlock?
  2. How can I verify, maybe using VS, that I do have a deadlock?
  3. Is it at Client.PostAsync? If yes why and how to fix it?
  4. If not, any ideas please.


Edit: Method A gets called using reflection with MethodInfo.Invoke. I believe now this is part of the problem.

解决方案

I believe you are seeing a deadlock, though I'm not sure how to prove it.

HttpClient on most platforms properly uses ConfigureAwait(false) internally, but on a few platforms does not. I believe that WP8 is one of those that does not. This means that you can use ConfigureAwait(false) all you want correctly, but HttpClient can still cause a deadlock.

The best solution is to go async all the way. But if that's not possible, then two alternatives come to mind:

  1. Push the HttpClient work off to a background thread.

    public Byte[] A()
    {
      var task = Task.Run(() => BAsync());
      return task.GetAwaiter().GetResult();
    }
    

  2. Establish a nested loop on the foreground thread to execute any asynchronous work.

    public Byte[] A()
    {
      return AsyncContext.Run(() => BAsync());
    }
    

    Note that AsyncContext is from my AsyncEx library. I believe AsyncContext should work on WP8 but I haven't actually used it on that platform.

这篇关于如何验证异步方法中的死锁和HttpClient.PostAsync调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆