我的主程序使用Task.Factory.StartNew運行8個任務如何異步解析來自HttpWebRequest的XML?
每個任務都會從webservice請求XML格式的結果,然後解析爲可以使用TVP寫入MSSQL的集合。
該程序的工作原理,但使用TPL的效率增益並非我所期望的。在各種情況下使用秒錶後,在我看來,這些任務正在相互干擾,也許一個阻塞另一個。所有數字都指向使用HttpWebRequest的下載部分。
在c#中的異步編程中搜索並閱讀了一點之後,我試圖修改我的代碼以異步運行下載部分,但結果仍然顯示相似級別的阻止,而不使用異步編碼。
有3種類型的代碼,我發現了幾個參考它們的鏈接:
How to use HttpWebRequest (.NET) asynchronously? - 當我用這個方法我通過了周圍的XDocument在下載部分方法,使用自定義對象
使用C#異步編程迭代 http://tomasp.net/blog/csharp-async.aspx -string /流被返回並在主方法,使用XDocument.Load /解析解析
下面的代碼塊顯示發現,在我的代碼實現
主要類的最後一個方法是在啓動任務
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);
}
的過程數據的方法
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。
下載數據部分:
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;
}
}
在過程數據的方法我定時從web服務下載所需要的代碼。 下載需要400ms到100000ms。正常時間在3000ms到8000ms左右。 如果我只運行1個任務,則客戶端進程時間僅比服務器進程時間稍長。
運行多個任務後然而,這需要450ms下載到3000ms(或其他)的服務器現在可能需要長達8000MS -90000ms客戶端完成下載部分。
我的方案的瓶頸應該在服務器端,從我的日誌它顯示的客戶端。
大多數爲異步編程發現的文章C#似乎演示讀取和處理流/字符串沒有XML的例子。我的代碼是否因爲XML而失敗?如果不是我的代碼有什麼問題?
編輯: 是我開發的機器和用戶/目標機器是XP,太多到.NET使用4.5或CTP。
ServicePointManager.DefaultConnectionLimit和app.config connectionManagement似乎是同樣的東西,所以我選擇了app.config,因爲它可以被更改。
起初改變最大連接幫助很大,但並沒有真正解決問題。 在使用Thread.Sleep(隨機)計時代碼塊之後,看起來「阻塞」並不涉及併發代碼。
從web服務的過程數據先下載(在這裏需要最大連接),然後做一些輕微的映射,最後寫數據庫,寫入數據庫從來沒有發生過1秒,相較於下載它是什麼,但增加最大連接後到DB(與webservice相同的數字),突然間沒有任何等待。
所以到DB最大的連接也很重要。但我不明白爲什麼用150-600ms寫入數據庫會導致等待超過20秒。
甚至讓我感到困惑的是等待時間是在下載塊中,而不是在寫入DB塊中。
給出4.0標記,我假設這不是一個選項,但如果/當你可以開始使用4.5,新的HttpClient類是'本地'異步,並使異步處理的響應更容易恕我直言 - http://msdn.microsoft.com/en-us/library/system.net.http.httpclient(VS.110).aspx –