[英]AddHttpClient<TClient,TImplementation> registers as transient, can it handle high volume concurrent requests efficiently?
I noticed that when using ASP.NET Core's IHttpClientFactory
, the typed client registration method AddHttpClient<TClient,TImplementation>
does two things:我注意到在使用 ASP.NET Core 的
IHttpClientFactory
时,类型化客户端注册方法AddHttpClient<TClient,TImplementation>
做了两件事:
It registers DI for <TClient,TImplementation>
as transient, as if calling services.AddTransient<TClient,TImplementation>
in startup.cs它将
<TClient,TImplementation>
的 DI 注册为瞬态,就像在 startup.cs 中调用services.AddTransient<TClient,TImplementation>
It will inject a HttpClient
instance of this registered type for each object initiated.它将为每个启动的 object 注入此注册类型的
HttpClient
实例。
My concern is, if this is configured as transient, will it be able to handle a large number of concurrent TImplementation
objects making http calls, because there will be a new HttpClient
as well as a new TClient
created for every call?我担心的是,如果将其配置为瞬态,它是否能够处理大量并发的
TImplementation
对象进行 http 调用,因为每次调用都会创建一个新的HttpClient
和一个新的TClient
? These clients will all access the same URL, will sockets be re-used properly?这些客户端都将访问相同的 URL,sockets 会被正确重用吗?
As King King has already pointed out the HttpMessageHandler
which matters.正如King King已经指出重要的
HttpMessageHandler
。
To better understanding how does it work I suggest to examine the DefaultHttpClientFactory
's source code .为了更好地理解它是如何工作的,我建议检查
DefaultHttpClientFactory
的源代码。
Let's take a look at the CreateClient method:我们来看看CreateClient方法:
public HttpClient CreateClient(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
HttpMessageHandler handler = CreateHandler(name);
var client = new HttpClient(handler, disposeHandler: false);
HttpClientFactoryOptions options = _optionsMonitor.Get(name);
for (int i = 0; i < options.HttpClientActions.Count; i++)
{
options.HttpClientActions[i](client);
}
return client;
}
As you can see it calls CreateHandler :如您所见,它调用CreateHandler :
public HttpMessageHandler CreateHandler(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
ActiveHandlerTrackingEntry entry = _activeHandlers.GetOrAdd(name, _entryFactory).Value;
StartHandlerEntryTimer(entry);
return entry.Handler;
}
Here we have a pool of handlers via _activeHandlers
.在这里,我们通过
_activeHandlers
有一个处理程序池。 And a factory method _entryFactory
, which is called when a given entry does not exist.还有一个工厂方法
_entryFactory
,当给定条目不存在时调用。 Let's take a look at their definitions:让我们看一下它们的定义:
_activeHandlers = new ConcurrentDictionary<string, Lazy<ActiveHandlerTrackingEntry>>(StringComparer.Ordinal);
_entryFactory = (name) =>
{
return new Lazy<ActiveHandlerTrackingEntry>(() =>
{
return CreateHandlerEntry(name);
}, LazyThreadSafetyMode.ExecutionAndPublication);
};
_expiredHandlers = new ConcurrentQueue<ExpiredHandlerTrackingEntry>();
So, as you can see it uses a Lazy
structure to minimize the cost of the initializations.因此,如您所见,它使用
Lazy
结构来最小化初始化成本。
The related CreateHandlerEntry
's source code can be found here if you are interested.相关的
CreateHandlerEntry
的源代码可以在这里找到,如果你有兴趣的话。
I also suggest to read Stephen Gordon's excellent article about this topic .我还建议阅读Stephen Gordon 关于这个主题的优秀文章。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.