Task.Factory.StartNewを使用して8つのタスクを実行する私のメインプログラム
各タスクは、WebサービスからXML形式の結果を要求し、TVPを使用してMSSQLに書き込むことができるコレクションに解析されます。
プログラムは動作しますが、TPLを使用した効率の向上は私が期待したものではありません。さまざまなポイントでストップウォッチを使用した後、タスクが互いに干渉しているように見えます。おそらく、一方が他方をブロックしているようです。すべての図は、HttpWebRequestを使用するダウンロードセクションを示しています。
C#で非同期プログラミングを少し検索して読んだ後、ダウンロードセクションを非同期で実行するようにコードを変更しようとしましたが、非同期コーディングを使用しなくても、同様のレベルのブロッキングが表示されます。
私が見つけたコーディングには3つのタイプがあり、それらへの参照リンクがいくつかあります。
HttpWebRequest(.NET)を非同期で使用するにはどうすればよいですか? -このメソッドを使用する場合、ダウンロードセクションメソッドでカスタムオブジェクトを使用してXDocumentを渡します
イテレータを使用したC#での非同期プログラミング http://tomasp.net/blog/csharp-async.aspx -string / streamが返され、mainメソッドでXDocument.Load/Parseを使用して解析されます
以下のコードブロックは、私のコードで見つかって実装された最後のメソッドを示しています
タスクを開始するメインクラス
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メソッド
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;
}
}
processDataメソッドで、Webサービスからダウンロードするために必要なコードの時間を計りました。ダウンロードには400msから100000msかかります。通常の時間は約3000msから8000msです。1つのタスクを実行しただけの場合、クライアントの処理時間はサーバーの処理時間よりわずかに長くなります。
ただし、さらにタスクを実行した後、サーバーで450ミリ秒から3000ミリ秒(またはその他)かかるダウンロードは、クライアントがダウンロードセクションを完了するのに最大8000ミリ秒から90000ミリ秒かかる可能性があります。
私のシナリオでは、ボトルネックはサーバー側にあるはずです。私のログから、クライアントがそうであることがわかります。
非同期プログラミングC#で見つかったほとんどの記事は、XMLの例がなくても、ストリーム/文字列の読み取りと処理のデモを行っているようです。XMLが原因でコードが失敗していませんか?そうでない場合、私のコードの問題は何ですか?
編集: はい、私の開発マシンとユーザー/ターゲットマシンはXPです。.net4.5またはCTPを使用するには多すぎます。
ServicePointManager.DefaultConnectionLimitとapp.configconnectionManagementは同じもののように見えるので、変更できるのでapp.configを選択します。
最初は最大接続を変更すると大いに役立ちますが、実際には問題を解決しませんでした。Thread.Sleep(random)を使用してコードブロックのタイミングを調整した後、「ブロッキング」は並行コードに関連していないようです。
processDataは最初にWebサービスからダウンロードし(ここでは最大接続が必要)、次にマイナーマッピングを実行し、最後にDBに書き込み、DBへの書き込みに1秒以上かかることはありません。ダウンロードと比較すると、何もありませんでしたが、DBに最大接続を追加した後(同じWebサービスとしての数)突然待つことはありませんでした。
したがって、DBへの最大接続も重要です。しかし、150〜600ミリ秒でDBに書き込むと、20秒以上待機する理由がわかりません。
私を混乱させるのは、待機時間がDBブロックの書き込みではなく、ダウンロードブロックにあったことです。