C# 等待任务结果时会发生什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12484112/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What happens while waiting on a Task's Result?
提问by scottt732
I'm using the HttpClient to post data to a remote service in a .NET 4.0 project. I'm not concerned with this operation blocking, so I figured I could skip ContinueWith or async/await and use Result.
我正在使用 HttpClient 将数据发布到 .NET 4.0 项目中的远程服务。我不关心这个操作阻塞,所以我想我可以跳过 ContinueWith 或 async/await 并使用 Result。
While debugging, I ran into an issue where the remote server wasn't responsive. As I stepped through the code, it seemed like my code just stopped running on the third line... the current stack pointer line stopped being highlighted yellow, and didn't advance to the next line. It just disappeared. It took me a while to realize that I should wait for the request to timeout.
在调试时,我遇到了远程服务器没有响应的问题。当我逐步执行代码时,似乎我的代码只是停止在第三行运行……当前堆栈指针行不再以黄色突出显示,并且没有前进到下一行。它只是消失了。我花了一段时间才意识到我应该等待请求超时。
var client = new HttpClient();
var task = client.PostAsync("http://someservice/", someContent);
var response = task.Result;
My understanding was that calling Result on the Task caused the code to execute synchronously, to behave more like this (I know there is no Post method in the HttpClient):
我的理解是在 Task 上调用 Result 会导致代码同步执行,表现得更像这样(我知道 HttpClient 中没有 Post 方法):
var client = new HttpClient();
var response = client.Post("http://someservice/", someContent);
I'm not sure this is a bad thing, I'm just trying to get my head around it. Is it really true that by virtue of the fact that the HttpClient is returning Tasks instead of the results directly, my application is automatically taking advantage of asynchrony even when I think I'm avoiding it?
我不确定这是件坏事,我只是想弄清楚。由于 HttpClient 返回的是 Tasks 而不是直接返回结果,我的应用程序是否会自动利用异步,即使我认为我正在避免它,这真的是真的吗?
采纳答案by Stephen Cleary
In Windows, all I/O is asynchronous. Synchronous APIs are just a convenient abstraction.
在 Windows 中,所有 I/O 都是异步的。同步 API 只是一种方便的抽象。
So, when you use HttpWebRequest.GetResponse, what actually happens is the I/O is started (asynchronously), and the calling thread (synchronously) blocks, waiting for it to complete.
因此,当您使用 时HttpWebRequest.GetResponse,实际发生的是 I/O 启动(异步),调用线程(同步)阻塞,等待它完成。
Similarly, when you use HttpClient.PostAsync(..).Result, the I/O is started (asynchronously), and the calling thread (synchronously) blocks, waiting for it to complete.
同样,当您使用 时HttpClient.PostAsync(..).Result,I/O 启动(异步),调用线程(同步)阻塞,等待它完成。
I usually recommend people use awaitrather than Task.Resultor Task.Waitfor the following reasons:
我通常建议人们使用await而不是Task.Result或Task.Wait出于以下原因:
- If you block on a
Taskthat is the result of anasyncmethod, you can easily get into a deadlock situation. Task.ResultandTask.Waitwrap any exceptions in anAggregateException(because those APIs are holdovers from the TPL). So error handling is more complex.
- 如果阻塞在方法
Task的结果上async,则很容易陷入死锁情况。 Task.Result并将Task.Wait任何异常包装在一个中AggregateException(因为这些 API 是来自 TPL 的保留)。所以错误处理更加复杂。
However, if you're aware of these limitations, there are some situations where blocking on a Taskcan be useful (e.g., in a Console application's Main).
但是,如果您了解这些限制,则在某些情况下阻止 aTask可能很有用(例如,在控制台应用程序的 中Main)。
回答by Atilla Baspinar
Capturing the result of a task blocks the current thread. There is no point in using a async version of a method in this case. Post()and PostAsync().Resultwill both block.
捕获任务的结果会阻塞当前线程。在这种情况下使用异步版本的方法没有意义。Post()并且PostAsync().Result都会阻塞。
If you want to make use of concurrency, you should write it as such:
如果你想使用并发,你应该这样写:
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;
}
Since PostContent()itself returns a Task, the method calling it should also await.
由于PostContent()本身返回一个任务,调用它的方法也应该等待。
async void ProcessResult()
{
var result = await PostContent();
//Do work with the result when the result is ready
}
For instance, if you call ProcessResult()in a button click handler, you see that the UI is still responsive, other controls still function.
例如,如果您调用ProcessResult()按钮单击处理程序,您会看到 UI 仍在响应,其他控件仍在运行。

