デシリアライゼーションと非同期/待機

私のアプリ(Windows 8 Metro)では、いくつかのオブジェクトがローカルフォルダにシリアル化された形式で保存されます。それから読む方法(以下を参照)があります。

Task.Runでこのメソッドを呼び出すと、オブジェクトを取得できます。

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

しかし、私がawaitキーワードを使用している場合、それは動作していません - メソッド内の行A(ReadObject)上で、スレッドはエラーまたは例外なしで停止して終了します:

var entity= await GetASync(file);

多分私はそれが推奨されているように待っている/非同期を使用しないでください?

この方法

private async Task GetASync(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;
    }
}
3
file = null の簡単なケースでは機能しますか?
追加された 著者 svick,
Result にアクセスしたくない場合、回避策は var entity = Task.Run (()=> GetASync /code>を非同期コードで使用します。
追加された 著者 Stephen Cleary,
svick、そうです
追加された 著者 MatthieuGD,

2 答え

まあ、あなたのコードがなぜ機能しないのか分かりません。私はデッドロックの疑いがありますが、 そのようにすべきではありません。 :)

しかし、私は副作用としておそらくこの問題を避けることができる2つのパフォーマンスの推奨事項を持っています。最初は ConfigureAwait(false)を使用することです:

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

もう1つは、ファイルを(非同期に)メモリに読み込み、それを解析することです。 (私はあなたのコードからファイルごとに1つのオブジェクトを格納していると仮定しています)。

3
追加された
ReadObject は同期です。したがって、読み込み中はスレッドプールスレッドをブロックします( ConfigureAwait を取り除くと、代わりにUIスレッドがブロックされます)。また、 IInputStream ラッパーは、非同期読み取りでブロックとして同期読み取りを実装しています。つまり、オブジェクトがさらに割り当てられています(例: ManualResetEvent )。最良の解決策は、 ReadObjectAsync ですが、AFAIKは存在しません(まだ)ので、非同期でファイルをメモリに読み込み、(同期的に)解析するという解決策があります。そうすれば、I/O上でスレッドプールスレッドがブロックされることはありません。
追加された 著者 Stephen Cleary,
なぜ動作するかについて:私は ReadObject のデッドロックが疑わしいと思っています。これは読み込み中にUIスレッドをブロックしていました。基礎となる非同期読み取りがUIスレッド(完了してはならない)で完了しようとすると、デッドロックが発生します。私はWinRTラッパーを調べましたが、どこでそれができるのかわかりませんでした。 ConfigureAwait は、読み取り操作が開始される前にUIコンテキストを削除することで機能します。そのため、基盤となる非同期読み取りはスレッドプールスレッドで完了します。しかし、それは必要ではないので、私にはバグがあります。
追加された 著者 Stephen Cleary,
Gragusの答えを確認してください。彼はそれが既知のバグであることを確認しました。将来のWin8ビルドで修正される予定です。
追加された 著者 Stephen Cleary,
ありがとう、スティーブン、最初のお勧めは、トリックでしたが、私はなぜか分からない...第2のもののために、私はパフォーマンスの問題を理解していない、あなたは説明することができますか?
追加された 著者 MatthieuGD,
詳細な説明をいただきありがとうございます.Windows 8の非同期/待機とプログラミングについての詳細は、まだ読んでおく必要があります。
追加された 著者 MatthieuGD,

http://からのPing-back /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);

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

1
追加された