我陷入了异步死锁,我无法弄清楚修复它的正确语法。我已经看了几个不同的解决方案,但似乎无法弄清楚导致问题的原因。
我使用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()
只是等待任务完成,然后返回正常操作。这不正确吗?
答案 0 :(得分:14)
您遇到了我描述on my blog和in a recent MSDN article的常见死锁问题。
简而言之,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;
....
}
}
答案 1 :(得分: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);
..
}
}