7

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

我使用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()只需等待任务完成,然后恢复正常操作即可。这不正确吗?

4

2 回答 2

14

您遇到了我在博客最近的 MSDN 文章中描述的常见死锁问题。

简而言之,await默认情况下将在捕获的“上下文”中恢复其async方法,并且在 ASP.NET 上,一次只允许一个线程进入该“上下文”。因此,当您调用 时Wait,您正在阻塞该上下文中的一个线程,并且当它准备好恢复该方法await时无法进入该上下文。async所以上下文中的线程被阻塞在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;
    ....

  }
}
于 2013-07-25T13:54:00.900 回答
1

您的问题是您正在混合同步和异步代码。这可以做到,但很棘手。你最好的选择是让你的 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);
..

        }
    }
于 2013-07-25T14:00:38.763 回答