8

Task.WaitUI スレッドで呼び出すのが悪いことはわかっています。デッドロックを引き起こします。を参照してください。

コンストラクターは非同期メソッドを呼び出します

待って、UI、そしてデッドロック!オーマイ!

次のコードを使用します。

    public MainPage()
    {
        this.InitializeComponent();

        step0();
        step1();
    }

    private async Task step0()
    {
        await Task.Delay(5000);
        System.Diagnostics.Debug.WriteLine("step 0");
    }

    private async Task step1()
    {
        await Task.Delay(3000);
        System.Diagnostics.Debug.WriteLine("step 1");
    }
}

「ステップ 0」が常に「ステップ 1」の前に印刷されるようにするにはどうすればよいですか? 使用Task.Waitするとデッドロックが発生します。これは Windows ストア アプリです

4

2 に答える 2

8

を使用Task.ContinueWithして、タスクを連鎖させて、順番に実行することができます。

public MainPage()
{
    this.InitializeComponent();

    step0().ContinueWith(t => step1());
}

また、アレクセイのコメントは正しいです。 UI スレッドTask.Waitブロックします。デッドロックは別のものです。

于 2012-11-16T06:11:34.313 に答える
5

asyncコンストラクターを使用することはできません。

したがって、何をするにしても、コンストラクターが初期化を完了せずasyncに戻る状況を処理する必要があります。

これを処理するにはいくつかの方法があります。「ステップ」がリソースをロードしている場合、次のようなことができます (私のブログ、Stephen Toub のブログ、または私のAsyncEx ライブラリのAsyncLazyタイプを使用- それらはすべてほぼ同じです):

private readonly AsyncLazy<MyResource> resource;

public MainPage()
{
  resource = new AsyncLazy<MyResource>(async () =>
  {
    var a = await step0();
    var b = await step1();
    return new MyResource(a, b); // or whatever
  });
  resource.Start(); // start step0
}

public async Task MethodThatNeedsResource()
{
  var r = await resource; // ensure step1 is complete before continuing
}

async voidメソッドやでこれを行うことも可能ContinueWithですが、これらのアプローチではエラー処理を慎重に検討する必要があります。

  • このAsyncLazyアプローチはエラーを捕捉し、await resource実行されるたびにエラーを発生させます。
  • このasync voidアプローチは、すぐにエラーをスローしSynchronizationContextます。
  • 素朴なContinueWithアプローチは、すべてのエラーを黙って無視します。

どちらのアプローチを取る場合でも、初期化が進行中であることを UI に通知することをお勧めします。(補足として、これはすべて ではなく ViewModel または Model クラスに入れる必要があると思いますMainPage)。

于 2012-11-16T13:50:28.890 に答える