web-dev-qa-db-ja.com

複数の待機対Task.WaitAll-同等?

パフォーマンスの観点から、これら2つのメソッドはGetAllWidgets()GetAllFoos()を並行して実行しますか?

一方を他方よりも使用する理由はありますか?コンパイラの背後で多くのことが起こっているようですので、わかりません。

============= MethodA:複数の待機を使用する=====================

public async Task<IHttpActionResult> MethodA()
{
    var customer = new Customer();

    customer.Widgets = await _widgetService.GetAllWidgets();
    customer.Foos = await _fooService.GetAllFoos();

    return Ok(customer);
}

=============== MethodB:Task.WaitAllを使用する=====================

public async Task<IHttpActionResult> MethodB()
{
    var customer = new Customer();

    var getAllWidgetsTask = _widgetService.GetAllWidgets();
    var getAllFoosTask = _fooService.GetAllFos();

    Task.WaitAll(new List[] {getAllWidgetsTask, getAllFoosTask});

    customer.Widgets = getAllWidgetsTask.Result;
    customer.Foos = getAllFoosTask.Result;

    return Ok(customer);
}

=====================================

46
vidalsasoon

最初のオプションは、2つの操作を同時に実行しません。最初のものを実行し、その完了を待ち、その後にのみ2番目のものを待ちます。

2番目のオプションは両方を同時に実行しますが、同期的に(つまり、スレッドをブロックしている間)待機します。

最初のオプションは2番目のオプションよりも完了が遅く、2番目のオプションは必要なくスレッドをブロックするため、両方のオプションを使用しないでください。

Task.WhenAllを使用して、両方の操作を非同期で待機する必要があります。

public async Task<IHttpActionResult> MethodB()
{
    var customer = new Customer();

    var getAllWidgetsTask = _widgetService.GetAllWidgets();
    var getAllFoosTask = _fooService.GetAllFos();

    await Task.WhenAll(getAllWidgetsTask, getAllFoosTask);

    customer.Widgets = await getAllWidgetsTask;
    customer.Foos = await getAllFoosTask;

    return Ok(customer);
}

Task.WhenAllが完了した後、両方のタスクがすでに完了しているので、それらを待つことはすぐに完了することに注意してください。

83
i3arnon

短い答え:いいえ。

_Task.WaitAll_はブロックしているため、awaitはタスクが検出されるとすぐにタスクを返し、関数と継続の残りの部分を登録します。

探していた「バルク」待機メソッドは_Task.WhenAll_で、これは実際に新しいTaskを作成し、関数に渡されたすべてのタスクが完了すると終了します。

そのように:await Task.WhenAll({getAllWidgetsTask, getAllFoosTask});

それはブロッキング問題です。

また、最初の関数は両方の関数を並行して実行しません。 awaitでこれを機能させるには、次のように記述する必要があります。

_var widgetsTask = _widgetService.GetAllWidgets();
var foosTask = _fooService.GetAllWidgets();
customer.Widgets = await widgetsTask;
customer.Foos = await foosTask;
_

これにより、最初の例は_Task.WhenAll_メソッドと非常によく似た動作をします。

15
Nitram

2番目のオプションのみがそれらを並行して実行します。最初の呼び出しは、各呼び出しを順番に待機します。

0
nvoigt

Asyncメソッドを呼び出すとすぐに実行が開始されます。現在のスレッドで実行する(したがって、同期的に実行する)か、非同期で実行するかを判断することはできません。

したがって、最初の例では、最初のメソッドが作業を開始しますが、その後、awaitを使用してコードのフローを人為的に停止します。したがって、2番目のメソッドは、最初のメソッドの実行が完了する前に呼び出されません。

2番目の例は、待機でフローを停止せずに両方のメソッドを呼び出します。したがって、メソッドが非同期の場合、潜在的に並列で実行されます。

0
Kasper Holdum