Наш веб-додаток працює у .Net Framework 4.0. Користувальницький інтерфейс викликає методи контролера через дзвінки ajax.
Нам потрібно споживати послугу REST від нашого постачальника. Я оцінюю найкращий спосіб зателефонувати в службу REST в. Net 4.0. Службі REST потрібна основна схема аутентифікації, і вона може повертати дані як у XML, так і в JSON. Немає вимоги до завантаження / завантаження величезних даних, і я нічого не бачу в майбутньому. Я переглянув кілька проектів з відкритим кодом для споживання REST і не знайшов у них жодної цінності, яка б виправдовувала додаткову залежність у проекті. Почав оцінювати WebClient
і HttpClient
. Я завантажив HttpClient для .Net 4.0 з NuGet.
Я шукав відмінності між WebClient
і, HttpClient
і цей сайт зазначив, що один HttpClient може обробляти одночасні дзвінки, і він може повторно використовувати вирішені DNS, конфігурацію файлів cookie та автентифікацію. Я ще не бачу практичних цінностей, які ми можемо отримати через розбіжності.
Я зробив швидкий тест на ефективність, щоб виявити, як WebClient
(синхронізувати дзвінки), HttpClient
(синхронізація та асинхронізація). і ось результати:
Використання одного і того ж HttpClient
екземпляра для всіх запитів (min - max)
Синхронізація WebClient: 8 мс - 167 мс
Синхронізація HttpClient: 3 мс - 7228 мс
Асинхронізація HttpClient: 985 - 10405 мс
Використання нового HttpClient
для кожного запиту (min - max)
Синхронізація WebClient: 4 мс - 297 мс
Синхронізація HttpClient: 3 мс - 7953 мс
Асинхронізація HttpClient: 1027 - 10834 мс
Код
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 Для початку дзвінки виконуються в іншому потоці і не блокують інтерфейс користувача. Отже, чи можу я просто дотримуватися синхронізації дзвінків?
- Вищевказаний код запускався в моєму локальному ящику. У налаштуваннях prod буде задіяно DNS та пошук проксі. Чи є якась перевага використання
HttpClient
надWebClient
? - Чи
HttpClient
паралельність краще, ніжWebClient
? З результатів тестування я бачу, щоWebClient
виклики синхронізації працюють краще. - Чи
HttpClient
стане кращим вибором дизайну, якщо ми перейдемо до .Net 4.5? Продуктивність є ключовим фактором дизайну.
GetDataFromHttpClientAsync
оскільки він запускається першим, інші виклики отримують користь від потенційно кешованих даних (будь то на локальній машині або будь-якого прозорого проксі між вами та пунктом призначення) і будуть швидшими. Крім того, за правильних умовvar response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;
може виникнути глухий кут через вас виснажливих ниток басейну. Ніколи не слід блокувати активність, яка залежить від пулу потоків у потоках ThreadPool,await
натомість слід повернути нитку назад у пул.