我们的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,cookie配置和身份验证。我还没有看到由于差异而可能获得的实用价值。
我进行了快速性能测试,以了解WebClient
(同步调用),HttpClient
(同步和异步)的性能。结果如下:
HttpClient
对所有请求使用同一实例(最小-最大)
WebClient同步:8毫秒-167毫秒
HttpClient同步:3毫秒-7228毫秒
HttpClient异步:985-10405毫秒
HttpClient
为每个请求使用一个新的(最小-最大)
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调用中调用。首先,调用在不同的线程中运行,并且不会阻止UI。所以,我可以坚持同步通话吗?
- 上面的代码在我的localbox中运行。在产品设置中,将涉及DNS和代理查找。使用
HttpClient
over 有什么优势WebClient
吗? - 是
HttpClient
并发比WebClient
?从测试结果中,我看到WebClient
同步调用的性能更好。 HttpClient
如果我们升级到.Net 4.5,将是更好的设计选择?性能是关键的设计因素。
GetDataFromHttpClientAsync
因为它首先运行,其他调用会受益于潜在的缓存数据(无论是在本地计算机上还是在您与目标之间的任何透明代理中),而且速度会更快。另外,在正确的条件下,var response = httpClient.GetAsync("http://localhost:9000/api/values/").Result;
由于耗尽线程池线程,可能导致死锁。您绝不应该阻止依赖ThreadPool线程中线程池的活动,而应该阻止await
它将线程返回到池中。