【问题标题】:Async Await Handler Deadlock异步等待处理程序死锁
【发布时间】:2016-12-22 23:40:35
【问题描述】:

我陷入了异步死锁,无法找出修复它的正确语法。我查看了几种不同的解决方案,但似乎无法完全弄清楚导致问题的原因。

我使用Parse 作为后端并尝试使用处理程序写入表。我的处理程序看起来像:

public class VisitorSignupHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        //Get the user's name and email address
        var UserFullName = context.Request.QueryString["name"].UrlDecode();
        var UserEmailAddress = context.Request.QueryString["email"].UrlDecode();

        //Save the user's information
        var TaskToken = UserSignup.SaveUserSignup(UserFullName, UserEmailAddress);
        TaskToken.Wait();
        ....

    }

    public bool IsReusable { get { return false; } }
}

然后它调用我的中间层:

public static class UserSignup
{
    public static async Task SaveUserSignup(string fullName, string emailAddress)
    {
        //Initialize the Parse client with the Application ID and the Windows key
        ParseClient.Initialize(AppID, Key);

        //Create the object
        var UserObject = new ParseObject("UserSignup")
                            {
                                {"UserFullName", fullName},
                                {"UserEmailAddress", emailAddress}
                            };

        //Commit the object
        await UserObject.SaveAsync();
    }
}

虽然这似乎卡在Wait()。我的印象是Wait() 只会等待任务完成,然后返回正常操作。这不正确吗?

【问题讨论】:

    标签: .net async-await parse-platform ihttphandler


    【解决方案1】:

    您遇到了一个常见的死锁问题,我描述了 on my blogin a recent MSDN article

    简而言之,await 默认情况下将在捕获的“上下文”中恢复其async 方法,而在 ASP.NET 上,一次只允许一个线程进入该“上下文”。因此,当您调用Wait 时,您正在阻塞该上下文中的一个线程,并且当准备恢复async 方法时,await 无法进入该上下文。所以上下文中的线程在Wait处被阻塞(等待async方法完成),而async方法被阻塞等待上下文空闲……死锁。

    要解决此问题,您应该“一直异步”。在这种情况下,请使用HttpTaskAsyncHandler 而不是IHttpHandler

    public class VisitorSignupHandler : HttpTaskAsyncHandler
    {
      public override async Task ProcessRequestAsync(HttpContext context)
      {
        //Get the user's name and email address
        var UserFullName = context.Request.QueryString["name"].UrlDecode();
        var UserEmailAddress = context.Request.QueryString["email"].UrlDecode();
    
        //Save the user's information
        var TaskToken = UserSignup.SaveUserSignup(UserFullName, UserEmailAddress);
        await TaskToken;
        ....
    
      }
    }
    

    【讨论】:

    • 谢谢!我在发布之前阅读了你的博客,只是不太明白语法。这很好用。欣赏它。
    • 不客气!附言好好阅读TAP documentation;这里有一些async 约定,特别是将SaveUserSignup 重命名为SaveUserSignupAsync
    • 你能帮我解决这个问题吗stackoverflow.com/questions/54001297/…
    【解决方案2】:

    您的问题是您正在混合同步和异步代码。这可以做到,但很棘手。最好的办法是让你的 http 处理程序也异步:

    public class VisitorSignupHandler : HttpTaskAsyncHandler
        {
            public override async Task ProcessRequestAsync(HttpContext context)
            {
               //Get the user's name and email address
               var UserFullName = context.Request.QueryString["name"].UrlDecode();
               var UserEmailAddress = context.Request.QueryString["email"].UrlDecode();
    
               //Save the user's information
               await UserSignup.SaveUserSignup(UserFullName, UserEmailAddress);
    ..
    
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-18
      • 2018-08-26
      相关资源
      最近更新 更多