在等待任务结果时会发生什么?

sco*_*732 36 c# asynchronous task

我正在使用HttpClient将数据发布到.NET 4.0项目中的远程服务.我不关心这个操作阻塞,所以我想我可以跳过ContinueWith或async/await并使用Result.

在调试时,我遇到了远程服务器没有响应的问题.当我逐步完成代码时,似乎我的代码在第三行停止运行...当前堆栈指针线停止突出显示为黄色,并且没有前进到下一行.它刚刚消失了.我花了一段时间才意识到我应该等待请求超时.

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

我的理解是调用任务上的Result导致代码同步执行,表现得更像这样(我知道HttpClient中没有Post方法):

var client = new HttpClient();
var response = client.Post("http://someservice/", someContent);
Run Code Online (Sandbox Code Playgroud)

我不确定这是件坏事,我只是试图理解它.真的是因为HttpClient正在返回Tasks而不是直接返回结果,我的应用程序即使在我认为我正在避免它时也会自动利用异步吗?

Ste*_*ary 43

在Windows中,所有I/O都是异步的.同步API只是一种方便的抽象.

因此,当您使用时HttpWebRequest.GetResponse,实际发生的是I/O启动(异步),并且调用线程(同步)阻塞,等待它完成.

类似地,当您使用时HttpClient.PostAsync(..).Result,I/O启动(异步),并且调用线程(同步)阻塞,等待它完成.

我通常建议人们使用await而不是Task.ResultTask.Wait出于以下原因:

  1. 如果阻止Task某个async方法的结果,则很容易陷入死锁状态.
  2. Task.Result并将Task.Wait任何异常包装AggregateException在一起(因为这些API是来自TPL的延期).因此错误处理更复杂.

但是,如果您了解这些限制,则在某些情况下,阻止a Task可能很有用(例如,在控制台应用程序中Main).

  • @Vukoje:自然异步操作(包括所有 I/O)应该由异步 API 表示。使用它们的正确方法是异步的,而不是同步的。如果开发人员“需要”同步使用异步 API,那么这总是表明使用应用程序中的设计错误(有时由于框架中的错误设计而不可避免,但通常只是应用程序中的错误设计)。 (2认同)