异步任务没有结束

Yur*_*yak 5 c# asynchronous windows-8 .net-4.5

我正在尝试启动异步任务(在.NET 4.5上)下载网页内容,但不知怎的,这个任务永远不会完成.

我的PageDownloader班级:

using System.Net;
using System.Text;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System;

namespace ParserConsole.WebClient
{
public class PageDownloader
{
    private System.Net.Http.HttpClient _client;

    public PageDownloader()
        : this(Encoding.UTF8) { }

    private Encoding _encoding;

    public PageDownloader(Encoding encoding)
    {
        _encoding = encoding;
        _client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10)};
    }

    private HttpRequestMessage _request;
    private HttpResponseMessage _response;
    private string _responseString;

    public string GetPageData(string link)
    {
        _request = new HttpRequestMessage(HttpMethod.Get, link);
        _request.Headers.Add("User-Agent", "Chrome/21.0.1180.89");
        _request.Headers.Add("Accept", "text/html");


        GetResponse().Wait();
        GetStringFromResponse().Wait();
        return _responseString;            
    }

    private async Task<HttpResponseMessage> GetResponse() {
        return _response = await _client.GetAsync(_request.RequestUri);
    }

    private async Task<string> GetStringFromResponse() {
        return _responseString = await _response.Content.ReadAsStringAsync();
    }

}
}
Run Code Online (Sandbox Code Playgroud)

我开始通过电话下载页面

new PageDownloader().GetPageData(url);
Run Code Online (Sandbox Code Playgroud)

当我试图调试代码时,一切都很好,直到GetResponse().Wait().但不知何故 GetResponse()任务永远不会完成 - 下一行的断点永远不会到达.我没有例外,应用程序继续运行.有什么建议?

Ser*_*rvy 9

这是您在启动async操作然后阻止返回的任务时获得的标准死锁条件.

是一篇关于该主题的博客文章讨论.

基本上,await调用确保它连接任务的延续将在你最初的上下文中运行(这是非常有用的)但是因为你Wait在相同的上下文中调用它是阻塞的,所以延续从不运行,并且继续需要为等待结束而奔跑.经典的僵局.

至于修复; 通常它意味着你不应该在异步操作上做阻塞等待; 这与整个系统的设计相反.你应该"一直异步".在这种情况下,它意味着GetPageData应该返回a Task<string>而不是a string,而不是等待返回任务的其他操作await.

现在,已经说过,有一些方法可以在没有死锁的情况下对异步操作进行阻塞等待.虽然可以做到,但它首先实际上违背了使用async/await的目的.使用该系统的主要优点是主要上下文不被阻止; 当你阻止整个优势消失时,你也可以一直使用阻塞代码. async/ await实际上更像是一个全有或全无的范例.

以下是我将如何构建该类:

public class PageDownloader
{
    private System.Net.Http.HttpClient _client;
    private Encoding _encoding;

    public PageDownloader()
        : this(Encoding.UTF8) { }

    public PageDownloader(Encoding encoding)
    {
        _encoding = encoding;
        _client = new HttpClient() { Timeout = TimeSpan.FromSeconds(10) };
    }

    public async Task<string> GetPageData(string link)
    {
        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, link);
        request.Headers.Add("User-Agent", "Chrome/21.0.1180.89");
        request.Headers.Add("Accept", "text/html");

        HttpResponseMessage response = await _client.GetAsync(request.RequestUri);

        return await response.Content.ReadAsStringAsync(); ;
    }
}
Run Code Online (Sandbox Code Playgroud)