우리의 웹 응용 프로그램은 .Net Framework 4.0에서 실행됩니다. UI는 아약스 호출을 통해 컨트롤러 메소드를 호출합니다.
공급 업체의 REST 서비스를 사용해야합니다. .Net 4.0에서 REST 서비스를 호출하는 가장 좋은 방법을 평가하고 있습니다. REST 서비스에는 기본 인증 체계가 필요하며 XML과 JSON으로 데이터를 리턴 할 수 있습니다. 대용량 데이터를 업로드 / 다운로드 할 필요가 없으며 앞으로는 아무것도 보이지 않습니다. REST 소비를위한 오픈 소스 코드 프로젝트를 몇 가지 살펴 보았고 프로젝트의 추가 종속성을 정당화 할 가치가 없었습니다. 평가하기 시작 WebClient
하고 HttpClient
. NuGet에서 .Net 4.0 용 HttpClient를 다운로드했습니다.
나는 차이를 검색 WebClient
하고 HttpClient
그리고 이 사이트는 그 하나의 HttpClient를 처리 할 수있는 동시 통화를 언급하며 DNS, 쿠키 설정 및 인증을 해결 재사용 할 수 있습니다. 차이로 인해 얻을 수있는 실질적인 가치를 아직 보지 못했습니다.
WebClient
(동기 호출), HttpClient
(동기 및 비동기) 수행 방법을 찾기 위해 빠른 성능 테스트를 수행했습니다. 결과는 다음과 같습니다.
HttpClient
모든 요청에 동일한 인스턴스 사용 (최소-최대)
WebClient 동기화 : 8ms -167ms
HttpClient 동기화 : 3ms
-7228ms HttpClient 비동기 : 985-10405ms
HttpClient
각 요청에 새로운 사용 (최소-최대)
WebClient 동기화 :
4ms-297ms HttpClient 동기화 : 3ms-7953ms
HttpClient 비동기 : 1027-10834ms
암호
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를 차단하지 않습니다. 동기화 호출을 계속 사용할 수 있습니까?
- 위의 코드는 내 로컬 박스에서 실행되었습니다. 제품 설정에서는 DNS 및 프록시 조회가 포함됩니다.
HttpClient
over 를 사용하면 어떤 이점이WebClient
있습니까? - 가
HttpClient
동시성보다 더WebClient
? 테스트 결과WebClient
동기화 호출이 더 잘 수행되는 것을 알 수 있습니다. - 윌
HttpClient
우리가 닷넷 4.5로 업그레이드하는 경우 더 나은 디자인 선택? 성능은 핵심 설계 요소입니다.
GetDataFromHttpClientAsync
먼저 실행되기 때문에 불공평하며 , 다른 호출은 잠재적으로 cahed 데이터 (로컬 시스템 또는 사용자와 대상 사이의 투명한 프록시 등)를 갖는 이점을 얻습니다. 또한 올바른 조건var response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;
에서 스레드 풀 스레드가 소진되어 교착 상태 가 발생할 수 있습니다. ThreadPool 스레드의 스레드 풀에 의존하는 활동을 차단해서는 안되며await
대신 스레드를 풀로 다시 리턴 해야 합니다.