首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从HttpWebRequest异步解析XML?

如何从HttpWebRequest异步解析XML?
EN

Stack Overflow用户
提问于 2012-06-15 09:33:06
回答 1查看 1K关注 0票数 0

我的主程序使用Task.Factory.StartNew运行8个任务

每个任务将请求来自webservice的XML格式结果,然后解析为集合,可以使用TVP写入MSSQL。

该程序工作,但效率提高使用TPL不是我所期望的。在不同的地方使用秒表后,在我看来,这些任务似乎是互相干扰的,也许是一个阻塞另一个。所有的数字指向使用HttpWebRequest的下载部分。

在对c#中的异步编程进行搜索和阅读后,我尝试修改代码以异步运行下载部分,但结果仍然显示出类似的阻塞级别,而不使用异步编码。

我发现了3种类型的编码以及一些指向它们的参考链接:

How to use HttpWebRequest (.NET) asynchronously? -When我使用此方法使用下载部分方法中使用自定义对象传递XDocument

在C#中使用迭代器返回异步编程,返回字符串/流,并在主方法中使用XDocument.Load/Parse进行解析。

下面的代码块显示了在我的代码中找到并实现的最后一个方法

启动任务的主类。

代码语言:javascript
复制
private static void test() {
    DBReader dbReader = new DBReader();
    Dictionary<string, DateTime> jobs = dbReader.getJob();
    JobHandler jh = new JobHandler();
    Stopwatch swCharge = new Stopwatch();
    Stopwatch swDetail = new Stopwatch();
    Stopwatch swHeader = new Stopwatch();
    //more stopwatch

    Task[] tasks = new Task[] {
    Task.Factory.StartNew(() => jh.processData<RawChargeCollection, RawCharge>(jobs["RawCharge"], 15, swCharge)),
    Task.Factory.StartNew(() => jh.processData<RawDetailCollection, RawDetail>(jobs["RawDetail"], 15, swDetail)),
    Task.Factory.StartNew(() => jh.processData<RawHeaderCollection, RawHeader>(jobs["RawHeader"], 15, swHeader))
    };
    Task.WaitAll(tasks);  
}

processData方法

代码语言:javascript
复制
public void processData<T, S>(DateTime x, int mins, Stopwatch sw)
            where T : List<S>, new()
            where S : new() {
            DateTime start = x;
            DateTime end = x.AddMinutes(mins);
            string fromDate, toDate;
            StringBuilder str = new StringBuilder();
            XMLParser xmlParser = new XMLParser();
            DBWriter dbWriter = new DBWriter();
            while (end <= DateTime.UtcNow) {
                fromDate = String.Format("{0:yyyy'-'MM'-'dd HH':'mm':'ss}", start);
                toDate = String.Format("{0:yyyy'-'MM'-'dd HH':'mm':'ss}", end);  
                try {
                    sw.Restart();
                    WebserviceClient ws = new WebserviceClient();

                    XDocument xDoc = null;
                    var task = ws.GetRawData<S>(fromDate, toDate);    
                    xDoc = XDocument.Parse(task.Result);    
                    //show the download time    

                    sw.Restart();
                    T rawData = xmlParser.ParseXML<T, S>(xDoc);

                    if (rawData.Count != 0) {
                        sw.Restart();
                        dbWriter.writeRawData<T, S>(rawData, start, end);
                        //log success
                    }
                    else {
                        //log no data
                    }
                }
                catch (Exception e) {
                    //log fail
                }
                finally { 
                    start = start.AddMinutes(mins);
                    end = end.AddMinutes(mins);
                }
            } 
        }

GetRawData只是负责构造GetData中所需的URL。

下载资料部分:

代码语言:javascript
复制
private static Task<string> GetData(string param) {
            string url = String.Format("my working URL/{0}", param);
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.MediaType = "application/xml";
            Task<WebResponse> task = Task.Factory.FromAsync(
                request.BeginGetResponse,
                asyncResult => request.EndGetResponse(asyncResult),
                (object)null);

            return task.ContinueWith(t => ReadStreamFromResponse(t.Result));
        }

    private static string ReadStreamFromResponse(WebResponse response) {
        using (Stream responseStream = response.GetResponseStream())
        using (StreamReader sr = new StreamReader(responseStream)) {
            //Need to return this response 
            string strContent = sr.ReadToEnd();
            return strContent;
        }
    }

在processData方法中,我计时了从webservice下载所需的代码。下载时间从400 to到100000ms不等。正常时间大约3000到8000毫秒。如果我只运行一个任务,客户端进程时间仅略长于服务器进程时间。

但是,在运行了更多的任务之后,服务器上需要450 to到3000 to (或其他任何东西)的下载现在可以占用8000 to 900 to,客户机才能完成下载部分。

在我的场景中,瓶颈应该在服务器端,从我的日志中可以看出客户机是。

大多数关于异步编程C#的文章似乎都演示了读取和处理流/字符串,而没有使用XML的示例。我的代码因为XML而失败吗??如果不是,我的代码有什么问题?

编辑:是的,我的开发机器和用户/目标机器是XP,太多了,无法使用.net 4.5或.net。

ServicePointManager.DefaultConnectionLimit和app.config connectionManagement似乎是一回事,所以我选择app.config,因为这是可以改变的。

起初,改变最大连接很有帮助,但并没有真正解决问题。在使用Thread.Sleep(随机)的定时代码块之后,“阻塞”似乎与并发代码无关。

processData首先从webservice下载(这里需要最大连接),然后执行一些小的映射,最后写到DB,向DB的写入永远不会超过1秒,与下载相比,它没有什么意义,但是在添加到DB的最大连接(与webservice相同的号码)之后,没有任何突然的等待。

因此,与DB的最大连接也很重要。但是我不明白为什么用150-600ms写到DB会导致超过20秒的等待。

甚至让我感到困惑的是等待时间是在下载块中,而不是在写DB块中。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-06-15 09:52:47

我会回到更简单的形式,至少在调试时,它们都是“正常”/同步代码。由于您将是最坏的情况下阻塞8个线程不必要,我不会认为这是一个大问题。

我可以想象,您所触及的是限制并发请求数量的默认行为。

从这个相关的线索..。

Max number of concurrent HttpWebRequests

...you可能想看看Jon所指的connectionManagement元素:

http://msdn.microsoft.com/en-us/library/fb6y0fyc.aspx

connectionManagement元素定义到服务器或服务器组的最大连接数。

此外,Jon建议用Thread.Sleep替换http调用,以查看并发性是否受到影响,这是很好的。如果您的8个任务都可以执行并行Thread.Sleep调用,那么您的问题不是“顶级”并发,而是由它们所执行的操作(比如默认的并发连接限制)强制执行的限制。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11048087

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档