2013-07-25 17 views
7

私は非同期デッドロックに陥っており、正しい構文を理解できません。私はいくつかの異なるソリューションを見てきましたが、問題の原因を突き止めることはできませんでした。非同期Awaitハンドラデッドロック

Parseをバックエンドとして使用しており、ハンドラを使用してテーブルに書き込もうとしています。これはWait()で立ち往生しているように見えるが、

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(); 
    } 
} 

:そして、それは私の中間層を呼び出している

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; } } 
} 

:私のハンドラは次のように見えます。私はWait()という仕事が完了するのを待ってから通常の操作に戻るという印象を受けました。これは間違っていますか?

答えて

13

私はon my blogin a recent MSDN articleという共通のデッドロック問題に遭遇しています。

要するに、デフォルトでawaitはキャプチャされた "コンテキスト"の内部でasyncメソッドを再開し、ASP.NETでは一度に1つのスレッドのみがそのコンテキストに許可されます。したがって、Waitと呼ぶと、そのコンテキスト内のスレッドをブロックしており、は、asyncメソッドを再開する準備ができたら、そのコンテキストに入ることができません。そのため、コンテキスト内のスレッドはWaitにブロックされ(asyncメソッドが完了するのを待っています)、asyncメソッドはブロックされ、コンテキストが解放されるのを待ってデッドロックされます。

これを修正するには、「すべて非同期」にする必要があります。この場合は、代わりにIHttpHandlerHttpTaskAsyncHandlerを使用します。

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; 
    .... 

    } 
} 
+0

ありがとうございます!私はこれを投稿する前にあなたのブログを読んで、構文を理解できませんでした。これは素晴らしいです。感謝します。 –

+1

あなたは大歓迎です! P.S. [TAPドキュメント](http://msdn.microsoft.com/en-us/library/hh873175.aspx)をよくお読みください。特にここでは 'SaveUserSignup'の名前を' SaveUserSignupAsync'に変更するという、いくつかの '非同期'の規約があります。 –

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); 
.. 

     } 
    }