[英]Async task does not end
我正在尝试启动异步任务(在.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();
}
}
}
我开始通过电话下载页面
new PageDownloader().GetPageData(url);
当我尝试调试代码时,一切都很好,直到GetResponse().Wait()
。 但不知何故, GetResponse()
任务永远不会完成 - 永远不会到达下一行的断点。 我没有例外,应用程序继续运行。 有什么建议?
这是您在启动async
操作然后阻止返回的任务时获得的标准死锁条件。
这是一篇关于该主题的博客文章讨论。
基本上, await
调用确保它连接任务的延续将在你最初的上下文中运行(这是非常有帮助的)但是因为你在同一个上下文中调用Wait
它是阻塞的,所以延续从不运行,并且延续需要运行等待结束。 经典的僵局。
至于修复; 通常它意味着你不应该在异步操作上做阻塞等待; 这与整个系统的设计相反。 你应该“一直异步”。 在这种情况下,它意味着GetPageData
应该返回一个Task<string>
而不是一个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(); ;
}
}
如果你想拥有这样的功能,为什么不这样做呢?
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");
var readTask = _client.GetStringAsync(link);
readTask.Wait();
return readTask.Result;
}
最好将Task一直返回并在调用代码中使用async / await处理它。
public Task<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");
return _client.GetStringAsync(link);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.