如何在并发中给 HttpClient 设置不同的超时时间?
Posted dotNET跨平台
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在并发中给 HttpClient 设置不同的超时时间?相关的知识,希望对你有一定的参考价值。
咨询区
boot4life
为了能够复用 HttpClient
所打开的TCP链接,我不得不让所有的request共享一个单例,但问题来了,如果我简单的在每一次request之前修改 timeout
属性的话,会存在下面两个问题。
线程不安全。
并发时可能会错用到其他 request 的超时配置。
请问我该如何正确的处理?
回答区
Todd Menier
你说的这种场景理论上是不可以设置 Timeout
属性,但不要忘了,你可以用 .NET 库中提供的取消机制类 CancellationTokenSource
,你可以在每一次 request 中带入 token 即可,然后用 CancelAfter()
方法来实现 Timeout 的功能,参考如下代码:
static async Task Main(string[] args)
var httpClient = new HttpClient();
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(30));
await httpClient.GetAsync("http://www.google.com", cts.Token);
哦,对了, HttpClient 的默认超时时间是 100s
,如果你在 CancelAfter
中设置了过大的超时时间,本质上来说并没有效果,为了解决这个 Max 的问题,我建议你给 HttpClient 设置一个无限期的超时,参考代码如下:
static async Task Main(string[] args)
var httpClient = new HttpClient();
httpClient.Timeout = System.Threading.Timeout.InfiniteTimeSpan;
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(30));
await httpClient.GetAsync("http://www.google.com", cts.Token);
Brad Albright
楼上的大佬说的非常好,但在我的场景下是这么实现的,首先我有一个默认的 CancellationToken
,它可被用户手工干预,另外还有一个 CancellationToken
,它是为了模拟 timeout 的 CancelAfter
,然后通过 CancellationTokenSource.CreateLinkedTokenSource
来将两者结合起来,就可以做到既可以被 timeout 结束也可以被用户手工干预停止,下面是我的案例代码:
public async static Task<HttpResponseMessage> SendRequest(CancellationToken cancellationToken)
var ctsForTimeout = new CancellationTokenSource();
ctsForTimeout.CancelAfter(TimeSpan.FromSeconds(5));
var cancellationTokenForTimeout = ctsForTimeout.Token;
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cancellationTokenForTimeout))
try
return await httpClient.GetAsync("http://asdfadsf", linkedCts.Token);
catch
//just for illustration purposes
if (cancellationTokenForTimeout.IsCancellationRequested)
Console.WriteLine("timeout");
else if (cancellationToken.IsCancellationRequested)
Console.WriteLine("other cancellation token cancelled");
throw;
点评区
说实话,用 CancellationToken
来替代 Timeout
机制确实是一个非常好的想法,如果大家细心的话,会发现 Framework 中很多涉及IO的操作都实现了这种 取消机制
,值得大家好好研究学习,比如下面代码:
public Task<HttpResponseMessage> DeleteAsync(Uri? requestUri, CancellationToken cancellationToken);
public Task<byte[]> GetByteArrayAsync(string? requestUri, CancellationToken cancellationToken);
public Task<Stream> GetStreamAsync(Uri? requestUri, CancellationToken cancellationToken);
public Task<string> GetStringAsync(string? requestUri, CancellationToken cancellationToken);
public Task<HttpResponseMessage> PutAsync(Uri? requestUri, HttpContent content, CancellationToken cancellationToken);
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken);
以上是关于如何在并发中给 HttpClient 设置不同的超时时间?的主要内容,如果未能解决你的问题,请参考以下文章