私たちのWebアプリは.Net Framework 4.0で実行されています。UIはajax呼び出しを通じてコントローラーメソッドを呼び出します。
ベンダーのRESTサービスを利用する必要があります。.Net 4.0でRESTサービスを呼び出す最良の方法を評価しています。RESTサービスは基本認証スキームを必要とし、XMLとJSONの両方でデータを返すことができます。巨大なデータをアップロード/ダウンロードする必要はなく、今後何も表示されません。RESTを使用するためのいくつかのオープンソースコードプロジェクトを調べたところ、プロジェクトに追加の依存関係を正当化するための価値が見つかりませんでした。評価WebClient
を開始しましたHttpClient
。NuGetから.Net 4.0用のHttpClientをダウンロードしました。
私は間の違いを検索WebClient
し、HttpClient
そしてこのサイトは、単一のHttpClientは同時コールを処理することができますし、それが解決DNS、クッキーの設定や認証を再利用できることを述べました。違いによって得られる実用的な値はまだわかりません。
WebClient
(同期呼び出し)、HttpClient
(同期および非同期)のパフォーマンスを確認するために、簡単なパフォーマンステストを行いました。そしてここに結果があります:
HttpClient
すべてのリクエストに同じインスタンスを使用する(最小-最大)
WebClient同期:8 ms-167 ms
HttpClient同期:3 ms-7228 ms
HttpClient async:985-10405 ms
HttpClient
リクエストごとに新しいものを使用する(最小-最大)
WebClient同期:4 ms-297 ms
HttpClient同期:3 ms-7953 ms
HttpClient async:1027-10834 ms
コード
public class AHNData
{
public int i;
public string str;
}
public class Program
{
public static HttpClient httpClient = new HttpClient();
private static readonly string _url = "http://localhost:9000/api/values/";
public static void Main(string[] args)
{
#region "Trace"
Trace.Listeners.Clear();
TextWriterTraceListener twtl = new TextWriterTraceListener(
"C:\\Temp\\REST_Test.txt");
twtl.Name = "TextLogger";
twtl.TraceOutputOptions = TraceOptions.ThreadId | TraceOptions.DateTime;
ConsoleTraceListener ctl = new ConsoleTraceListener(false);
ctl.TraceOutputOptions = TraceOptions.DateTime;
Trace.Listeners.Add(twtl);
Trace.Listeners.Add(ctl);
Trace.AutoFlush = true;
#endregion
int batchSize = 1000;
ParallelOptions parallelOptions = new ParallelOptions();
parallelOptions.MaxDegreeOfParallelism = batchSize;
ServicePointManager.DefaultConnectionLimit = 1000000;
Parallel.For(0, batchSize, parallelOptions,
j =>
{
Stopwatch sw1 = Stopwatch.StartNew();
GetDataFromHttpClientAsync<List<AHNData>>(sw1);
});
Parallel.For(0, batchSize, parallelOptions,
j =>
{
Stopwatch sw1 = Stopwatch.StartNew();
GetDataFromHttpClientSync<List<AHNData>>(sw1);
});
Parallel.For(0, batchSize, parallelOptions,
j =>
{
using (WebClient client = new WebClient())
{
Stopwatch sw = Stopwatch.StartNew();
byte[] arr = client.DownloadData(_url);
sw.Stop();
Trace.WriteLine("WebClient Sync " + sw.ElapsedMilliseconds);
}
});
Console.Read();
}
public static T GetDataFromWebClient<T>()
{
using (var webClient = new WebClient())
{
webClient.BaseAddress = _url;
return JsonConvert.DeserializeObject<T>(
webClient.DownloadString(_url));
}
}
public static void GetDataFromHttpClientSync<T>(Stopwatch sw)
{
HttpClient httpClient = new HttpClient();
var response = httpClient.GetAsync(_url).Result;
var obj = JsonConvert.DeserializeObject<T>(
response.Content.ReadAsStringAsync().Result);
sw.Stop();
Trace.WriteLine("HttpClient Sync " + sw.ElapsedMilliseconds);
}
public static void GetDataFromHttpClientAsync<T>(Stopwatch sw)
{
HttpClient httpClient = new HttpClient();
var response = httpClient.GetAsync(_url).ContinueWith(
(a) => {
JsonConvert.DeserializeObject<T>(
a.Result.Content.ReadAsStringAsync().Result);
sw.Stop();
Trace.WriteLine("HttpClient Async " + sw.ElapsedMilliseconds);
}, TaskContinuationOptions.None);
}
}
}
私の質問
- REST呼び出しは3〜4秒で戻りますが、これは許容範囲です。RESTサービスの呼び出しは、ajax呼び出しから呼び出されるコントローラーメソッドで開始されます。まず、呼び出しは別のスレッドで実行され、UIをブロックしません。だから、私は同期呼び出しだけを続けることができますか?
- 上記のコードは私のlocalboxで実行されました。製品のセットアップでは、DNSとプロキシのルックアップが関係します。
HttpClient
以上に使用する利点はありますWebClient
か? - ある
HttpClient
並行処理は、より良いですかWebClient
?テスト結果から、WebClient
同期呼び出しのパフォーマンスが向上していることがわかり ます。 - ウィル
HttpClient
我々は純4.5にアップグレードする場合は、より良い設計上の選択でありますか?パフォーマンスは重要な設計要素です。
GetDataFromHttpClientAsync
最初に実行されるため、不公平です。他の呼び出しは、データ(ローカルマシン上、または宛先との間の透過的なプロキシ上にある)を潜在的にキャッシュし、より高速になります。また、適切な条件下では、var response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;
スレッドプールスレッドを使い果たしてデッドロックが発生する可能性があります。ThreadPool threadsのスレッドプールに依存するアクティビティをブロックしないでください。await
代わりに、スレッドがプールに返されるようにする必要があります。