C#异步方法还挂着UI [英] C# async methods still hang UI

查看:84
本文介绍了C#异步方法还挂着UI的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这两种方法,我想异步运行,以保持UI响应。但是,它仍然挂在UI。有什么建议?

 异步无效DoScrape()
    {
        VAR饲料=新饲料();        VAR的结果=等待feed.GetList();
        的foreach(在结果VAR itemObject)
        {
            VAR项目=新的ListViewItem(itemObject.Title);
            item.SubItems.Add(itemObject.Link);
            item.SubItems.Add(itemObject.Description);
            LstResults.Items.Add(项目);
        }
    }
    公共类饲料
    {
        异步公共任务<名单,LT; ItemObject>>的GetList()
        {
            VAR的客户=新的WebClient();
            字符串内容=等待client.DownloadStringTaskAsync(新的URI(anyUrl));
            VAR lstItemObjects =新的List< ItemObject>();
            VAR饲料=新的XmlDocument();
            feed.LoadXml(内容);
            VAR节点= feed.GetElementsByTagName(项目);            的foreach(在节点XmlNode的节点)
            {
                VAR tmpItemObject =新ItemObject();
                VAR标题=节点[标题];
                如果(标题!= NULL)tmpItemObject.Title = title.InnerText;
                VAR链接=节点[链接];
                如果(链接!= NULL)tmpItemObject.Link = link.InnerText;
                Var描述=节点[说明];
                如果(说明!= NULL)tmpItemObject.Description = description.InnerText;
                lstItemObjects.Add(tmpItemObject);
            }
            返回lstItemObjects;
        }
    }


解决方案

我怀疑 DownloadStringTaskAsync 依赖<一个href=\"http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse.aspx\"><$c$c>HttpWebRequest.BeginGetResponse在一个较低的水平。既然如此,它已知为一的WebRequest设置不完全异步的。烦人(坦白地说,愚蠢)是同步执行异步的WebRequest的DNS查找阶段,因此块。我怀疑这可能是你所观察的问题。

转载如下

在文档警告:


  

的BeginGetResponse方法需要一些同步设置任务来完成(DNS解析,代理此方法之前检测和TCP套接字连接,例如)变为异步的。其结果是,这种方法不应该上的用户界面(UI)线程调用,因为它可能需要一些时间,通常是几秒钟。在其中webproxy脚本没有正确配置某些环境中,这可能需要60秒或更多。为配置文件元素的downloadTime属性的默认值为1分钟占大多数的潜在时间延迟。


您已经两个选择:


  1. 启动从一个工作线程的请求(高负荷下运行的线程池饥饿的风险,由于阻止行为)

  2. (云林)执行之前发射要求的纲领性DNS查找。这被异步完成。希望请求将然后使用缓存DNS查找。

我们去了3号(和昂贵的)实现我们自己的正常异步HTTP库获得体面的吞吐量选项,但它可能是你的情况有点极端;)

I have these two methods, that I want to run async to keep the UI responsive. However, it's still hanging the UI. Any suggestions?

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;
        }
    }

解决方案

I suspect DownloadStringTaskAsync relies upon HttpWebRequest.BeginGetResponse at a lower level. This being the case, it is known that the setup for a webrequest is not fully asynchronous. Annoyingly (and frankly, stupidly) the DNS lookup phase of an asynchronous WebRequest is performed synchronously, and therefore blocks. I suspect this might be the issue you are observing.

Reproduced below is a warning in the docs:

The BeginGetResponse method requires some synchronous setup tasks to complete (DNS resolution, proxy detection, and TCP socket connection, for example) before this method becomes asynchronous. As a result, this method should never be called on a user interface (UI) thread because it might take some time, typically several seconds. In some environments where the webproxy scripts are not configured properly, this can take 60 seconds or more. The default value for the downloadTime attribute on the config file element is one minute which accounts for most of the potential time delay.

You've two choices:

  1. Start the request from a worker thread (and under high load, run the risk of ThreadPool starvation due to blocking behaviour)
  2. (Tenuously) Perform a programmatic DNS lookup prior to firing the request. This can be done asynchronously. Hopefully the request will then use the cached DNS lookup.

We went for the 3rd (and costly) option of implementing our own properly asynchronous HTTP library to get decent throughput, but it's probably a bit extreme in your case ;)

这篇关于C#异步方法还挂着UI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆