47

HttpClientを使用して、.NET4.0プロジェクトのリモートサービスにデータを投稿しています。私はこの操作のブロックには関心がないので、ContinueWithまたはasync/awaitをスキップしてResultを使用できると考えました。

デバッグ中に、リモートサーバーが応答しないという問題が発生しました。コードをステップ実行すると、コードが3行目で実行を停止したように見えました...現在のスタックポインタ行が黄色で強調表示されなくなり、次の行に進みませんでした。消えたばかりです。リクエストがタイムアウトするのを待つ必要があることに気付くのに少し時間がかかりました。

var client = new HttpClient();
var task = client.PostAsync("http://someservice/", someContent);
var response = task.Result;

私の理解では、タスクでResultを呼び出すと、コードが同期的に実行され、次のように動作します(HttpClientにPostメソッドがないことはわかっています)。

var client = new HttpClient();
var response = client.Post("http://someservice/", someContent);

これが悪いことかどうかはわかりませんが、頭を悩ませているだけです。HttpClientが結果ではなくタスクを直接返すという事実のおかげで、私がそれを避けていると思っていても、私のアプリケーションは自動的に非同期を利用しているというのは本当に本当ですか?

4

2 に答える 2

55

Windowsでは、すべてのI/Oは非同期です。同期APIは便利な抽象化です。

したがって、を使用するHttpWebRequest.GetResponseと、実際に発生するのはI / Oが(非同期で)開始され、呼び出し元のスレッドが(同期的に)ブロックして、完了するのを待機することです。

同様に、を使用するHttpClient.PostAsync(..).Resultと、I / Oが(非同期で)開始され、呼び出し元のスレッドが(同期的に)ブロックされ、完了するのを待ちます。

私は通常、次の理由でawaitはなく、Task.ResultまたはTask.Wait次の理由で使用することをお勧めします。

  1. メソッドTaskの結果であるをブロックすると、デッドロック状態に陥りやすくなります。async
  2. Task.Result例外をでTask.WaitラップしますAggregateException(これらのAPIはTPLからのホールドオーバーであるため)。したがって、エラー処理はより複雑です。

ただし、これらの制限を認識している場合は、でのブロックTaskが役立つ場合があります(たとえば、コンソールアプリケーションの場合Main)。

于 2012-09-18T20:32:25.393 に答える
4

タスクの結果をキャプチャすると、現在のスレッドがブロックされます。この場合、メソッドの非同期バージョンを使用しても意味がありません。両方ともブロックしますPost()PostAsync().Result

並行性を利用したい場合は、次のように記述する必要があります。

async Task PostContent()
{
  var client = new HttpClient();
  Task t = await client.PostAsync("http://someservice/", someContent);
  //code after this line will execute when the PostAsync completes.
  return t;
}

それPostContent()自体がタスクを返すため、それを呼び出すメソッドも待機する必要があります。

async void ProcessResult()
{
   var result = await PostContent(); 
   //Do work with the result when the result is ready 
}

たとえばProcessResult()、ボタンクリックハンドラーを呼び出すと、UIが引き続き応答し、他のコントロールが機能していることがわかります。

于 2017-04-27T08:02:22.473 に答える