我在这里尝试做的是循环一个充满 URL 的 ListView ,检查源代码是否包含字符串,如果包含则用 YES 或 NO< 更新 UI ListView .
我忘记了 Parallel.ForEach 方法,所以决定尝试一下(我什至不确定这是否是最佳解决方案)
Parallel.ForEach(listViewMain.Items.Cast<ListViewItem>(), row =>
{
try
{
string html = Helpers.GetRequest(row.Text);
if (html.Contains(txtBoxFind.Text))
{
row.SubItems[3].Text = "YES";
}
else
{
row.SubItems[3].Text = "NO";
}
} catch(Exception) {
}
});
在没有 Parallel.ForEach 的情况下,这个过程相当简单,但是 UI 仍然锁定,我实现了吗? Helpers.GetRequest 只是返回要检查的原始 HTML,我认为使用 Parallel.ForEach 会在处理时停止 UI 锁定,或者我弄错了,任何帮助都是赞赏。
请您参考如下方法:
在我们开始之前,请注意 Parallel.ForEach 本身是一个阻塞调用,因此这就是您遇到 UI 没有响应的原因。
好的读物是 Avoid Executing Parallel Loops on the UI Thread 来自 MS 文档:
... the parallel loop blocks the UI thread on which it’s executing until all iterations are complete.
也就是说,如果不处理 CPU 绑定(bind)工作而是处理 I/O 绑定(bind)工作,您应该使用基于 Task 的方法。由于您正在处理网络调用,因此您应该坚持执行任务。试试这个:
public async Task DoSomething()
{
// Process the items parallel
await Task.WhenAll(listViewMain.Items.Cast<ListViewItem>().Select(async row =>
{
// wrap the long running call in a async Task
string html = await Task.Run(() => Helpers.GetRequest(row.Text));
// no need for context capturing and invokes, this is running on the UI thread
var containsText = html.Contains(txtBoxFind.Text);
if (containsText)
{
row.SubItems[3].Text = "YES";
}
else
{
row.SubItems[3].Text = "NO";
}
}));
}
如果您可以使 Helpers.GetRequest(row.Text) 成为基于任务的方法,那就更好了,您可以这样做:
public async Task DoSomething()
{
// Process the items parallel
await Task.WhenAll(listViewMain.Items.Cast<ListViewItem>().Select(async row =>
{
// wrap the long running call in a async Task
string html = await Helpers.GetRequestAsync(row.Text);
// no need for context capturing and invokes, this is running on the UI thread
var containsText = html.Contains(txtBoxFind.Text);
if (containsText)
{
row.SubItems[3].Text = "YES";
}
else
{
row.SubItems[3].Text = "NO";
}
}));
}
但我们需要查看 Helpers.GetRequest(row.Text) 的代码来帮助您。
编辑
您已经展示了 GetRequest 的代码。 WebClient 不是基于任务的,试试 HttpClient:
public async Task<string> GetRequestAsync(string url)
{
var html = "";
using (HttpClient wc = new HttpClient())
{
html = await wc.GetStringAsync(url);
}
return html;
}
