web-dev-qa-db-ja.com

タスク内で非同期/待機を待機しています

私はmain()にこの構造を持っています。

_var tasks = new List<Task>();

var t = Task.Factory.StartNew(
    async () =>
    {
        Foo.Fim();
        await Foo.DoBar();
    });

//DoBar not completed
t.Wait();
//Foo.Fim() done, Foo.DoBar should be but isn't
_

ただし、tに_.Wait_を指定すると、DoBar()の呼び出しが完了するまで待機しません。実際に待つにはどうすればよいですか?

44
Nathan Cooper

Task.Factory.StartNewasync-awaitを使用することは推奨されません。代わりにTask.Runを使用する必要があります。

var t = Task.Run(
    async () =>
    {
        Foo.Fim();
        await Foo.DoBar();
    });

Task.Factory.StartNew apiは、 タスクベースの非同期パターン(TAP) およびasync-awaitの前に構築されました。ラムダ式でタスクを開始しているため、たまたま非同期でタスクを返すため、Task<Task>を返します。 Unwrapは内部タスクを抽出しますが、Task.Runは暗黙的にそれを行います。


より詳細な比較のために、関連するStephen Toubの記事が常にあります: Task.Run vs Task.Factory.StartNew

90
i3arnon

タスクをUnwrap() ingすることで、必要な機能が得られるようです。この背後にある理由を理解できるかどうかはよくわかりませんが、うまくいくと思います。

_var t = Task.Factory.StartNew(
            async () =>
                {
                        Foo.Fim();
                        await Foo.DoBar();
                }).Unwrap();
_

編集:Unwrap()の説明を探しました:_Creates a proxy Task that represents the asynchronous operation of a Task<Task<T>>_これは伝統的にタスクがやったことだと思っていましたが、unwrapを呼び出す必要があるならそれでいいと思います。

5
Nathan Cooper

私は最近、同様の問題に直面し、あなたがする必要があるのは、DoBar()が何らかの値を返し、待機の代わりに.Resultを使用することであることがわかりました。

var g = Task.Run(() => func(arg));

var val = g.Result;

これは、funcが出力を返し、valに割り当てるのを待ちます。

1