4

私が取り組んでいる単純なasync例があり、期待どおりに実行が呼び出し元に返されません。awaitトップレベルのメソッドは次のとおりです。

protected async void MyDDL_SelectedIndexChanged(object sender, EventArgs e)
{
  Task longRunningTask = LongRunningOperationAsync();
  DoOtherStuff1();
  DoOtherStuff2();
  DoOtherStuff3();
  await longRunningTask;
}

LongRunningOperationAsync期待どおりに動作せず、同期的に実行されるメソッドを次に示します。

 private async Task LongRunningOperationAsync()
 {
   var myValues = await GetStuffViaLongRunningTask();
   //Code to work with myValues here...
 }

の定義は次のとおりです。GetStuffViaLongRunningTask

private async Task<IList<MyClass>> GetStuffViaLongRunningTask()
{

    //...Calls to get and build up IList<MyClass>
    return results;

}

問題は、上記のコードが呼び出し元に戻らDoOtherStuff1();、期待どおりにメソッドの実行を開始しないことです。await Task.Delay(10000);ただし、独自のメソッドを呼び出して、すべての単純な例が示すように呼び出しに置き換える代わりに、コードは期待どおりに機能します。

 private async Task LongRunningOperationAsync()
 {
   //Returns to caller as expected:
   await Task.Delay(10000);
 }

上記のコードを使用している呼び出し元はlongRunningTaskWaitingForActivationステータスが ではなく でありRanToCompletion、まだ処理中であることを示しています。

私のGetStuffViaLongRunningTask()方法は非常に速く実行され、結果が表示されないだけだと言うかもしれません。ただし、実行には常に 3 ~ 7 秒かかるため、デバッグ時に、呼び出しがブロックされ、同期されていることがわかります。

そのメソッド内で呼び出す単語LongRunningOperationAsync()に到達したときに、への呼び出しが非同期に機能しないように、ここで間違って何をしていますか?awaitLongRunningOperationAsync

4

2 に答える 2

3

//...Calls to get and build up IList<MyClass>それが同期 CPU バウンド作業であると仮定すると、そこにある問題はGetStuffViaLongRunningTask、それが終了するか、最初のawait呼び出しに到達するまで返されません。asyncそのメソッドには が含まれていないため、コンパイラの警告が表示されるはずですawait

async代わりに、同期作業であることを呼び出し元に明確に示すために、メソッドを にするべきではありません。署名を次のように調整するだけです。

private IList<MyClass> GetStuffViaLongRunningTask()

次に、それを呼び出すときにTask.Run、長時間実行される CPU バウンドの作業が別のスレッドで行われるようにします。

private async Task LongRunningOperationAsync()
{
    var myValues = await Task.Run(() => GetStuffViaLongRunningTask());
    //Code to work with myValues here...
}
于 2013-10-07T19:20:56.423 に答える
1

//...Calls to get and build up IList<MyClass>

どの通話が行われているかを示す必要があります。この構造で async/await を使用する場合は、async 呼び出しを行う必要があります。

GetStuffViaLongRunningTask関数が非同期呼び出しを行っていない場合は、次のように新しいタスクを開始できます。

private Task<IList<MyClass>> GetStuffViaLongRunningTask()
{
    return Task.Factory.StartNew(() =>
    {
        //...Calls to get and build up IList<MyClass>
        // You can make synchronous calls here
        return list;
    });
}
于 2013-10-07T19:22:20.840 に答える