获取请求等待的时间超过timeoutPolicy
超时。
var timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(30), TimeoutStrategy.Optimistic);
var watch = new Stopwatch();
try
{
watch.Start();
var httpResponse = await timeoutPolicy.ExecuteAsync(
async ct => await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://google.com"), ct),
CancellationToken.None
);
watch.Stop();
Console.WriteLine("request took " + watch.ElapsedMilliseconds);
}
catch (Exception e)
{
watch.Stop();
Console.WriteLine("timeout took " + watch.ElapsedMilliseconds);
Console.WriteLine(e.Message);
}
答案 0 :(得分:1)
我想我已经玩够了,知道发生了什么,所以我有信心现在可以回答这个问题。
当您使用async
的Polly策略调用TimeoutStrategy.Optimistic
任务时,您传入的是CancellationToken
并实质上相信将调用CancellationToken
来结束任务超时情况。
与TimeoutStrategy.Pesimistic
策略的行为不同,该策略旨在终止不通过CancellationToken
进行回调的同步任务。
虽然您的主执行线程没有被在另一个线程上运行的异步任务阻止,但重要的是要记住该任务确实能够阻止它自己的线程。
例如,如果异步任务要调用Thread.Sleep(1000)
,则该线程的线程将被阻塞一秒钟。这反过来意味着CancellationToken
不能在块的持续时间内被调用。
在这种情况下,我认为长时间运行的操作(例如,首次查找主机名的DNS记录)或正在发生的其他任何阻止操作实际上将阻止线程90ms。
这样,即使任务知道它需要在30ms标记处中止,它也需要等待线程可用,然后才能实际调用取消,直到大约90ms左右才会发生取消
对于每个域解析来说,这种返回超时的延迟似乎只是第一次出现,因此我认为这与名称服务器缓存和DNS解析有关,因为后续调用似乎可以更有效地兑现超时。尽管断言任何直接的根本原因在很大程度上是猜测。