Aplikasi web kami berjalan di .Net Framework 4.0. UI memanggil metode pengontrol melalui panggilan ajax.
Kita perlu mengkonsumsi layanan REST dari vendor kami. Saya mengevaluasi cara terbaik untuk memanggil layanan REST di .Net 4.0. Layanan REST memerlukan Skema Otentikasi Dasar dan dapat mengembalikan data dalam XML dan JSON. Tidak ada persyaratan untuk mengunggah / mengunduh data besar dan saya tidak melihat apa pun di masa depan. Saya melihat beberapa proyek kode sumber terbuka untuk konsumsi REST dan tidak menemukan nilai pada mereka untuk membenarkan ketergantungan tambahan dalam proyek. Mulai mengevaluasi WebClient
dan HttpClient
. Saya mengunduh HttpClient untuk .Net 4.0 dari NuGet.
Saya mencari perbedaan antara WebClient
dan HttpClient
dan situs ini menyebutkan bahwa HttpClient tunggal dapat menangani panggilan bersamaan dan dapat menggunakan kembali DNS, konfigurasi cookie, dan otentikasi yang diselesaikan. Saya belum melihat nilai-nilai praktis yang dapat kita peroleh karena perbedaan.
Saya melakukan tes kinerja cepat untuk mengetahui kinerja WebClient
(sinkronisasi panggilan), HttpClient
(sinkronisasi dan asinkron). dan inilah hasilnya:
Menggunakan HttpClient
contoh yang sama untuk semua permintaan (minimal maks)
Sinkronisasi WebClient: 8 ms - 167 ms
HttpSinkronisasi klien: 3 ms - 7228 ms
HttpClient async: 985 - 10405 ms
Menggunakan yang baru HttpClient
untuk setiap permintaan (minimum)
Sinkronisasi WebClient: 4 ms - 297 ms
HttpSinkronisasi klien: 3 ms - 7953 ms
HttpClient async: 1027 - 10834 ms
Kode
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);
}
}
}
Pertanyaan saya
- Panggilan REST kembali dalam 3-4 yang dapat diterima. Panggilan ke layanan REST dimulai dengan metode pengontrol yang dipanggil dari panggilan ajax. Untuk mulai dengan, panggilan berjalan di utas yang berbeda dan tidak memblokir UI. Jadi, bisakah saya tetap dengan panggilan sinkronisasi?
- Kode di atas dijalankan di kotak lokal saya. Dalam pengaturan prod, DNS dan pencarian proxy akan terlibat. Apakah ada keuntungan menggunakan
HttpClient
lebihWebClient
? - Apakah
HttpClient
konkurensi lebih baik daripadaWebClient
? Dari hasil pengujian, saya melihatWebClient
panggilan sinkronisasi berkinerja lebih baik. - Akankah
HttpClient
menjadi pilihan desain yang lebih baik jika kita meningkatkan ke .Net 4.5? Kinerja adalah faktor desain utama.
GetDataFromHttpClientAsync
karena berjalan terlebih dahulu, pemanggilan lainnya mendapatkan manfaat dari berpotensi memiliki data cahed (baik itu di mesin lokal atau proxy transparan antara Anda dan tujuan) dan akan lebih cepat. Selain itu, dalam kondisi yang tepatvar response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;
dapat menyebabkan kebuntuan karena Anda melelahkan ulir threadpool. Anda seharusnya tidak pernah memblokir aktivitas yang bergantung pada kumpulan utas di utas ThreadPool, Anda harus memblokirnyaawait
sehingga mengembalikan utas kembali ke kumpulan.