191

void asyncメソッドがジョブを終了するのをどのように待つことができますか?

たとえば、次のような関数があります。

async void LoadBlahBlah()
{
    await blah();
    ...
}

ここで、他の場所に進む前に、すべてがロードされていることを確認したいと思います。

4

6 に答える 6

302

ベストプラクティスはasync void、それがファイアアンドフォーゲットメソッドである場合にのみ関数をマークすることです。待ちたい場合は、それをとしてマークする必要がありますasync Task

それでも待ちたい場合は、そのようにラップしてくださいawait Task.Run(() => blah())

于 2012-11-30T02:17:28.257 に答える
62

関数のシグネチャをに変更できる場合は、ここasync Taskに示すコードを使用できます

于 2012-11-30T00:36:41.357 に答える
30

最善の解決策はを使用することasync Taskです。async voidいくつかの理由で避ける必要があります。その1つは構成可能性です。

メソッドを返すことができないTask場合(たとえば、イベントハンドラーの場合)、SemaphoreSlimメソッドが終了しようとしているときにメソッドシグナルを受け取るために使用できます。finallyこれをブロックで行うことを検討してください。

于 2012-11-30T02:21:20.273 に答える
5

手動で何もする必要はありません。awaitキーワードは、blah()戻るまで関数の実行を一時停止します。

private async void SomeFunction()
{
     var x = await LoadBlahBlah(); <- Function is not paused
     //rest of the code get's executed even if LoadBlahBlah() is still executing
}

private async Task<T> LoadBlahBlah()
{
     await DoStuff();  <- function is paused
     await DoMoreStuff();
}

Tオブジェクトのタイプがblah()返されます

あなたは本当に機能することができないのでawait、することはできませんvoidLoadBlahBlah()void

于 2012-11-30T01:24:26.733 に答える
1

AutoResetEventを実行し、関数を呼び出してからAutoResetEventを待機し、完了したことがわかったらasyncvoid内に設定します。

voidasyncから戻るタスクを待つこともできます

于 2013-08-23T20:34:50.120 に答える
1

私はこれが古い質問であることを知っていますが、これは私が歩き続ける問題です、それでも非同期void署名メソッドでasync/awaitを使用するときにこれを正しく行うための明確な解決策はまだありません。

ただし、voidメソッド内で.Wait()が正しく機能していることに気付きました。

また、async voidとvoidは同じシグニチャを持っているため、次のことを行う必要がある場合があります。

void LoadBlahBlah()
{
    blah().Wait(); //this blocks
}

紛らわしいことに、十分なasync/awaitは次のコードをブロックしません。

async void LoadBlahBlah()
{
    await blah(); //this does not block
}

コードを逆コンパイルすると、非同期voidが内部タスクを作成すると思いますが(非同期タスクと同じように)、署名はその内部タスクを返すことをサポートしていないためです

これは、内部的に非同期voidメソッドが内部的に非同期メソッドを「待機」できることを意味します。しかし、内部タスクがいつ完了したかを外部から知ることはできません。

したがって、私の結論は、非同期voidが意図したとおりに機能しているということです。内部タスクからのフィードバックが必要な場合は、代わりに非同期タスク署名を使用する必要があります。

うまくいけば、私のとりとめのない話は、答えを探している人にとっても理にかなっています。

編集:私はいくつかのサンプルコードを作成し、それを逆コンパイルして実際に何が起こっているかを確認しました。

static async void Test()
{
    await Task.Delay(5000);
}

static async Task TestAsync()
{
    await Task.Delay(5000);
}

になります(編集:本文コードはここではなくステートマシンにあることはわかっていますが、ステートマシンは基本的に同一であるため、わざわざ追加する必要はありませんでした)

private static void Test()
{
    <Test>d__1 stateMachine = new <Test>d__1();
    stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
    stateMachine.<>1__state = -1;
    AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
    <>t__builder.Start(ref stateMachine);
}
private static Task TestAsync()
{
    <TestAsync>d__2 stateMachine = new <TestAsync>d__2();
    stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
    stateMachine.<>1__state = -1;
    AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder;
    <>t__builder.Start(ref stateMachine);
    return stateMachine.<>t__builder.Task;
}

AsyncVoidMethodBuilderもAsyncTaskMethodBuilderも、実際にはStartメソッドに、ブロックするように示唆するコードがなく、開始後に常に非同期で実行されます。

つまり、タスクが返されない場合、タスクが完了したかどうかを確認する方法はありません。

予想どおり、非同期で実行されているタスクを開始するだけで、コード内で続行されます。非同期タスクでは、最初にタスクを開始し、次にそれを返します。

だから私の答えは、タスクがいつ実行されるかを知る必要がある場合は、非同期タスクを使用しないことだと思います。それが非同期タスクの目的です。

于 2020-01-15T15:19:43.990 に答える