2011-12-18 20 views
3

私のアプリ(Windows 8 Metro)では、いくつかのオブジェクトをローカルフォルダにシリアル化された形式で格納します。それから読む方法(以下を参照)があります。この方法でラインA(readObjectメソッド)に -逆シリアル化と非同期/待機

var entity= Task.Run<Entity>(() => GetASync<Entity>(file)).Result; 

が、私はのawaitキーワードを使用している場合、それは働いていない:

私はTask.Runでこのメソッドを呼び出すと、私は、オブジェクトを取得することができますスレッドが停止し、エラーまたは例外なしで終了:それはお勧めしますよう

var entity= await GetASync<Entity>(file); 

は、たぶん私はのawait /非同期使用していませんか?

方法

private async Task<T> GetASync<T>(IStorageFile file) where T : class 
{ 
    try 
    {  
     if (file != null) 
     { 
      IRandomAccessStream readStream = await file.OpenAsync(FileAccessMode.Read); 
      IInputStream inputStream = readStream.GetInputStreamAt(0);     
      using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(inputStream.AsStream(), XmlDictionaryReaderQuotas.Max)) 
      { 
       DataContractSerializer serializer = new DataContractSerializer(typeof(T)); 
       var entity = serializer.ReadObject(reader); //line A - here the problem 
       return entity as T; 
      }      
     } 
     else 
     { 
      return null; 
     } 

    } 
    catch (FileNotFoundException) 
    { 
     return null; 
    } 
    catch (Exception) 
    { 
     throw; 
    } 
} 
+0

'file = null'の簡単なケースでは機能しますか? – svick

+0

svick、そうです – MatthieuGD

+0

回避策は 'var entity = Wait Task.Run (()=> GetASync (file));' '非同期コードで' Result'にアクセスしたくない場合、別の方法でエラーを処理するためです。 –

答えて

3

まあ、私はあなたのコードが動作しない理由はわかりません。私はデッドロックの疑いがありますが、ではありません。 :)

しかし、私はおそらく副作用として問題を回避するいくつかの推奨事項を持っています。

IRandomAccessStream readStream = await file.OpenAsync(FileAccessMode.Read) 
              .StartAsTask() 
              .ConfigureAwait(false); 

他方は(非同期に)メモリにファイルを読み取り、次いでそれを解析することである:最初は、ConfigureAwait(false)を使用することです。 (私はあなたのコードからファイルごとに1つのオブジェクトを格納していると仮定しています)。

+0

スティーブン、最初の勧告はトリックでしたが、私はなぜ分かりません...第2のものについては、私はパフォーマンスの問題を理解していない、あなたは説明することができますか? – MatthieuGD

+0

'ReadObject'は同期です。したがって、読み込み中はスレッドプールスレッドをブロックします( 'ConfigureAwait'を取り出した場合は、代わりにUIスレッドをブロックします)。また、 'IInputStream'ラッパーは、非同期読み取りでは同期読み取りをブロックとして実装しています。つまり、割り当てられているオブジェクトが増えています(例えば、' ManualResetEvent')。最良の解決策は 'ReadObjectAsync'ですが、AFAIKは存在しません(まだ)ので、非同期でファイルをメモリに読み込み、それを(同期的に)解析するという解決策があります。そうすれば、I/O上でスレッドプールスレッドがブロックされることはありません。 –

+0

*なぜ*動作しているのか:私は、読み込み中にUIスレッドをブロックしていた 'ReadObject'のデッドロックを疑います。基礎となる非同期読み取りがUIスレッド(完了してはならない)で完了しようとすると、デッドロックが発生します。私はWinRTラッパーを調べましたが、どこでそれができるのかわかりませんでした。 'ConfigureAwait'は、読み込み操作が始まる前にUIコンテキストを取り除くことによって動作します。そのため、基本の非同期読み込みはスレッドプールスレッドで完了します。しかし、それは必要ではないので、私にはバグがあります。 –

1

ピンポン​​バックhttp://social.msdn.microsoft.com/Forums/en-US/async/thread/3f192a81-073a-47ea-92e2-5ce02bf5ad33から:

あなたは、MicrosoftがBUILDカンファレンスで配布.NETの開発者向けプレビュー版の既知の問題をヒットしています。 この問題は、WinRT UIスレッドの細部に起因しています。その結果、UIスレッドから実行された場合、マネージコードからのブロッキングWinRTストリームIOによってデッドロックが発生します。非同期IO(例:ReadAsync)は正常に動作します。開発チームは問題を認識しており、問題の修正に取り組んでいます。

ただし、問題が修正された場合でも、UIスレッドでブロックIOを実行することはお勧めできません。アプリケーションは、処理中にブロックされ、応答しなくなります。一部の.NET APIには(まだ)非同期の非同期関数はなく、一度変換してもコード変換が必要な場合があります。 IOをブロックする操作を行う必要がある場合は、スレッドプールにオフロードする必要があります。

DoUIStuff(); 
Int32 x = await Task.Run(() => { 
    OpenStream(); 
    PerformBlockingIO(); 
    ProcessResults(); 
    return ComputeIOResults(); 
}); 
UseIOResults(x); 

このようにして、アプリケーションを常に応答性の高い状態に保ちます。副作用として、上記のバグを回避してデッドロックを回避することもできます。

関連する問題