我有一个web应用程序。我发现性能瓶颈可能是我为每个请求一次又一次地创建Http客户端。
public static class DemoHttpClient
{
public static HttpClient GetClient()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(DemoConstants.DemoAPI);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
}
public class DemoConstants
{
public const string DemoAPI = "http://localhost/";
}
我正计划为此实施singleton。我发现这篇文章很有帮助。http://csharpindepth.com/Articles/General/Singleton.aspx
当ASP.NET MVC web应用程序部署在服务器上时,我对它的生命周期究竟是如何的感到困惑。假设将有多个线程调用同一资源,则该资源会一次又一次地生成新的http客户端。。
我们在这里该怎么办。。1) 懒惰地加载HTTP客户端?2) 不是懒洋洋地装?
我们应该使用哪种特定的方法?
这听起来不是个好主意。特别是,看一下HttpClient
类的文档:
此类型的任何公共静态(在Visual Basic中共享)成员都是线程安全的。任何实例成员都不能保证是线程安全的。
https://msdn.microsoft.com/en-us/library/system.net.http.httpclient%28v=vs.118%29.aspx
这意味着从多个线程访问同一个singleton实例将导致未定义的问题。
然而,可以做的是,可以在单个请求中重用同一个实例。这可以通过在Items
容器中存储一个实例来实现:
private static string ITEMSKEY = "____hclient";
public static HttpClient GetClient()
{
if ( HttpContext.Current.Items[ITEMSKEY] == null )
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(DemoConstants.DemoAPI);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpContext.Current.Items.Add( ITEMSKEY, client );
}
return (HttpClient)HttpContext.Current.Items[ITEMSKEY];
}
请注意,由于HttpClient
实现了IDisposable
,因此在管道中的某个位置(例如在应用程序管道的EndRequest
事件中)处理此类实例仍然是一个好主意。
更新:正如@LukeH的评论中所指出的,.NET 4.5和4.6文档的更新版本指出,HttpClient
类的一些方法是线程安全的:
https://msdn.microsoft.com/en-us/library/system.net.http.httpclient%28v=vs.110%29.aspx
更新的备注部分指出,单个实例基本上是应用于该实例执行的所有请求的共享设置的集合。然后,医生说:
此外,每个HttpClient实例都使用自己的连接池,将其请求与其他HttpClient实例执行的请求隔离开来。
这意味着隔离不同的池仍然是有意义的,我个人的建议仍然是不要使用singleton,因为您可能仍然需要在连续请求之间更改一些设置。