Webclient DownloadString 冻结主窗体
Webclient DownloadString Freezing the main Form
希望有人能帮我解决我的问题。
我正在尝试使用以下代码获取网站的 html 代码:
public string DownloadString(string add)
{
string html = "";
using (WebClient client = new WebClient())
{
client.Proxy = null;
client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
while (html == "")
{
try
{
html = client.DownloadString(add);
}
catch (WebException e)
{
html = "";
}
}
client.Dispose();
}
return html;
}
我需要这个函数中的字符串(调用方):
public HtmlNode get_html(string add)
{
add_val(add);
Uri madd = new Uri(add);
Stopwatch timer = Stopwatch.StartNew();
Task<string> task = Task.Factory.StartNew<string>
(() => DownloadString(add));
string html = task.Result;
//string html = DownloadString(add);
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
//doc.Load(new StringReader(html));
doc.LoadHtml(html);
HtmlNode root = doc.DocumentNode;
timer.Stop();
TimeSpan timespan = timer.Elapsed;
label18.Text = String.Format("{0:00}:{1:00}:{2:00}", timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10);
return root;
}
我试过 html = await client.DownloadStringTaskAsync(new Uri(add));
但它似乎不起作用,当我下载一个字符串时它仍然冻结 UI。
提前致谢!
为了防止阻塞 UI,您的代码需要一直异步 。
此代码特别阻塞 UI 线程,直到下载完成:
Task<string> task = Task.Factory.StartNew<string>(() => DownloadString(add));
string html = task.Result;
您需要的是使用 await
代替:
Task<string> task = Task.Run(() => DownloadString(add));
string html = await task;
这意味着您的 get_html
方法必须是 async
:
public async Task<HtmlNode> get_htmlAsync(string add)
并且它的所有调用者都必须使用 await
,然后变成 async
,等等。您必须允许异步在调用者树中一直增长。
这里的问题是对 task.Result
的调用总是阻塞的(如果任务没有准备好,调用线程将等待完成),所以你的 UI 线程将被阻塞,等待任务结果。如果您使用的是 .Net Framework 4(@Stephen 为 4.5 编写了一个解决方案),您需要做的是按以下方式使用延续。
public void get_html(string add)
{
add_val(add);
Uri madd = new Uri(add);
Stopwatch timer = Stopwatch.StartNew();
Task.Factory.StartNew<string>(() => DownloadString(add))
.ContinueWith(t => {
string html = task.Result;
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
HtmlNode root = doc.DocumentNode;
timer.Stop();
TimeSpan timespan = timer.Elapsed;
label18.Text = String.Format("{0:00}:{1:00}:{2:00}", timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10);
//
Update UI with results here
//
}, TaskScheduler.FromCurrentSynchronizationContext());
}
或者您可以将 get_html
return 类型设置为 Task<string>
或 Task<HtmlNode>
以便在其上使用延续。
希望有人能帮我解决我的问题。
我正在尝试使用以下代码获取网站的 html 代码:
public string DownloadString(string add)
{
string html = "";
using (WebClient client = new WebClient())
{
client.Proxy = null;
client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");
while (html == "")
{
try
{
html = client.DownloadString(add);
}
catch (WebException e)
{
html = "";
}
}
client.Dispose();
}
return html;
}
我需要这个函数中的字符串(调用方):
public HtmlNode get_html(string add)
{
add_val(add);
Uri madd = new Uri(add);
Stopwatch timer = Stopwatch.StartNew();
Task<string> task = Task.Factory.StartNew<string>
(() => DownloadString(add));
string html = task.Result;
//string html = DownloadString(add);
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
//doc.Load(new StringReader(html));
doc.LoadHtml(html);
HtmlNode root = doc.DocumentNode;
timer.Stop();
TimeSpan timespan = timer.Elapsed;
label18.Text = String.Format("{0:00}:{1:00}:{2:00}", timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10);
return root;
}
我试过 html = await client.DownloadStringTaskAsync(new Uri(add));
但它似乎不起作用,当我下载一个字符串时它仍然冻结 UI。
提前致谢!
为了防止阻塞 UI,您的代码需要一直异步 。
此代码特别阻塞 UI 线程,直到下载完成:
Task<string> task = Task.Factory.StartNew<string>(() => DownloadString(add));
string html = task.Result;
您需要的是使用 await
代替:
Task<string> task = Task.Run(() => DownloadString(add));
string html = await task;
这意味着您的 get_html
方法必须是 async
:
public async Task<HtmlNode> get_htmlAsync(string add)
并且它的所有调用者都必须使用 await
,然后变成 async
,等等。您必须允许异步在调用者树中一直增长。
这里的问题是对 task.Result
的调用总是阻塞的(如果任务没有准备好,调用线程将等待完成),所以你的 UI 线程将被阻塞,等待任务结果。如果您使用的是 .Net Framework 4(@Stephen 为 4.5 编写了一个解决方案),您需要做的是按以下方式使用延续。
public void get_html(string add)
{
add_val(add);
Uri madd = new Uri(add);
Stopwatch timer = Stopwatch.StartNew();
Task.Factory.StartNew<string>(() => DownloadString(add))
.ContinueWith(t => {
string html = task.Result;
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(html);
HtmlNode root = doc.DocumentNode;
timer.Stop();
TimeSpan timespan = timer.Elapsed;
label18.Text = String.Format("{0:00}:{1:00}:{2:00}", timespan.Minutes, timespan.Seconds, timespan.Milliseconds / 10);
//
Update UI with results here
//
}, TaskScheduler.FromCurrentSynchronizationContext());
}
或者您可以将 get_html
return 类型设置为 Task<string>
或 Task<HtmlNode>
以便在其上使用延续。