我有这两种方法,我想运行异步来保持UI响应。但是,它仍然悬挂着UI。有什么建议吗?
async void DoScrape()
{
var feed = new Feed();
var results = await feed.GetList();
foreach (var itemObject in results)
{
var item = new ListViewItem(itemObject.Title);
item.SubItems.Add(itemObject.Link);
item.SubItems.Add(itemObject.Description);
LstResults.Items.Add(item);
}
}
public class Feed
{
async public Task<List<ItemObject>> GetList()
{
var client = new WebClient();
string content = await client.DownloadStringTaskAsync(new Uri("anyUrl"));
var lstItemObjects = new List<ItemObject>();
var feed = new XmlDocument();
feed.LoadXml(content);
var nodes = feed.GetElementsByTagName("item");
foreach (XmlNode node in nodes)
{
var tmpItemObject = new ItemObject();
var title = node["title"];
if (title != null) tmpItemObject.Title = title.InnerText;
var link = node["link"];
if (link != null) tmpItemObject.Link = link.InnerText;
var description = node["description"];
if (description != null) tmpItemObject.Description = description.InnerText;
lstItemObjects.Add(tmpItemObject);
}
return lstItemObjects;
}
}
答案 0 :(得分:12)
我怀疑DownloadStringTaskAsync
在较低级别依赖HttpWebRequest.BeginGetResponse
。在这种情况下,已知webrequest的设置不是完全异步的。恼人地(坦率地说,愚蠢地)异步WebRequest的DNS查找阶段是同步执行的,因此会阻塞。我怀疑这可能是你正在观察的问题。
以下转载的是文档中的警告:
你有两个选择:
我们选择了实现我们自己的正确异步HTTP库的第三个(也是代价高昂的)选项来获得不错的吞吐量,但在你的情况下它可能有点极端;)
答案 1 :(得分:5)
你似乎混淆了并行异步。它们都基于任务,但它们完全不同。不要假设async
方法并行运行 - 它们不会。
异步默认工作在相同的线程,除非有理由强制异步引擎启动新线程,例如主线程没有消息泵的情况。但总的来说,我倾向于认为async
关键字在同一个线程中运行。
您使用WinForms,因此UI线程有一个消息泵。因此,上面的所有代码都在UI线程中运行。
您必须了解此处 NOT 引入了任何并行性。您通过async
关键字引入的内容是异步操作, NOT 并行。您没有采取任何措施来“让您的用户界面响应”除了对DownloadStringTaskAsync
的一次调用,这不会强迫您等待数据到达,但您仍然必须做UI线程中的所有网络处理(DNS查找等) - 这是正在进行的异步操作(基本上“节省”等待下载的时间)。
为了保持UI的响应性,您需要将耗时的工作分拆到单独的线程中,同时保持UI线程的自由。您没有使用async
关键字执行此操作。
您需要使用Task.Factory.StartNew(...)
显式启动新线程来进行后台处理。
答案 2 :(得分:4)
您在列表视图中添加了多少项?
除非您采取措施阻止它,否则每次将项目添加到列表中时,WinForms列表视图都会执行批次处理。这可能需要很长时间才能添加100个项目可能需要几秒钟。
尝试在循环中使用BeginUpdate
和EndUpdate
来推迟ListView的簿记,直到完成为止。
async void DoScrape()
{
var feed = new Feed();
var results = await feed.GetList();
LstResults.BeginUpdate(); // Add this
try
{
foreach (var itemObject in results)
{
var item = new ListViewItem(itemObject.Title);
item.SubItems.Add(itemObject.Link);
item.SubItems.Add(itemObject.Description);
LstResults.Items.Add(item);
}
}
finally
{
LstResults.EndUpdate();
}
}
如果出现异常,最后要尝试避免各种各样的痛苦。