28

アプリケーションの起動時に設定ファイルを読み込んで読み込もうとしていますが、約 90% のawait GetFileAsync("filename.xml");確率で返されないため、アプリケーションがハングします。

約 4 分の 1 の確率で、コードをステップ実行すると、実際に戻ってファイルが読み取られます。

コードの非常に単純化されたバージョンを次に示します。

アプリ.xaml.cs:

protected override void OnLaunched(LaunchActivatedEventArgs args)
{
    FileLoader.Load().Wait();

    // File-load dependent stuff
}

FileLoader.cs:

public async static Task Load()
{
    StorageFolder folder = ApplicationData.Current.LocalFolder;
    StorageFile file;
    bool fileExists = true;

    try
    {
        // The following line (often) never returns
        file = await folder.GetFileAsync("filename.xml");
    {
    catch
    {
        fileExists = false;
    }

    // Do stuff with loaded file
}

Visual Studio で出力ウィンドウを見ると、しばらく待ってから"The thread '<No Name>' (0x30c) has exited with code 0 (0x0)."

ここで何が起こっているのか誰か知っていますか?

4

1 に答える 1

54

デフォルトでは、まだ完了していない場合、メソッドはキャプチャされたコンテキスト (この場合は UI コンテキスト) で再開されますawaitTask

したがって、コードが失敗する理由は次のとおりです。

  • OnLaunched呼び出しLoad(UI コンテキスト内)。
  • Load待っています。これにより、Loadメソッドは未完了のタスクを返し、その完了を後でスケジュールします。この継続は、UI コンテキストでスケジュールされています。
  • OnLaunchedから返されたタスクのブロックLoad。これにより、UI スレッドがブロックされます。
  • GetFileAsync最終的に完了し、 の継続を実行しようとしますLoad
  • LoadUI コンテキストで実行できるように、UI スレッドが使用可能になるのを待機するための継続。
  • この時点で、OnLaunchedは完了するのを待っておりLoad(そうすることで UI スレッドをブロックします)、LoadUI スレッドが解放されるのを待っています。デッドロック。

これらのベスト プラクティスは、この状況を回避します。

  1. 「ライブラリ」asyncメソッドでは、ConfigureAwait(false)可能な限り使用してください。あなたの場合、これは に変わりawait folder.GetFileAsync("filename.xml");ますawait folder.GetFileAsync("filename.xml").ConfigureAwait(false);
  2. Tasksでブロックしないでください。それasyncはずっと下がっています。つまり、 に置き換えWaitますawait

詳細については:

更新、2012 年 7 月 13 日:この回答をブログ投稿に組み込みました

于 2012-07-03T20:03:28.310 に答える