我们有一个 .NET 4.7.2,它混合使用异步和同步代码(我知道这是禁忌)。我们在 Windows 服务上使用 NancyFX。该服务获取休息调用并进行休息调用。线程池看起来很健康(整个进程只使用了 70 个线程)。由于某种原因,某些 http 响应延迟了 10 秒,有时延迟了 100 秒,并导致任务取消。
以下是代码的结构
public async Task<Guid> SomeFunction()
{
...
var response = await _httpClient.SendAsync(request, cancellationToken);
...
}
SomeFunction().Result
首先,我确信由于某种原因,响应在网络上的某个地方被延迟了。但我们已经通过多种方式排除了这一点,最重要的是通过 perfview 查看 ETW 跟踪并查看数据包几乎立即返回(使用 Microsoft-Windows-NDIS-PacketCapture/PacketFragment)
其次,我确信这与异步方法上的 .Result 代码引起的线程池问题有关。然而,进程上的线程再次稳定在 70 个线程。通过 perfview 我可以看到饥饿确实没有发生(使用 Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThreadAdjustment/Adjustment)
我还以为我可能会遇到await/async 和.Result 的死锁情况,但死锁意味着请求永远不会完成,而不是它会延迟10 秒。
我还仔细检查过我们只使用了一个 httpclient 实例,而且确实如此。
还能是什么?
此时,我们正在删除 .Result 并将其替换为适当的 async/await。但我没有证据表明这会解决问题,因为我没有看到任何死锁或线程耗尽的证据。
我们还在研究有关我们正在以某种方式耗尽 http 连接的建议。我认为情况并非如此的原因之一是,根据 perfview,请求正在发送并且数据包返回,但响应并没有组成 c# 堆栈。然而,这些性能计数器可能表明存在一些排队现象。
更新 我们已经增加了 http 连接,并且似乎已经生效。
<connectionManagement>
<add address="*" maxconnection="1024"/>
</connectionManagement>
上面显示的排队完全消失了。然而,这些请求未完成的问题仍然存在
最佳答案
What else could it be?
您已经检查了我的第一个猜测,即线程池饥饿。
还有另一种可能性,具体取决于 API 调用的完成方式。如果同一主机有多个同时请求,则 .NET 网络堆栈可能会限制您的速度。非 ASP.NET 应用程序默认限制对同一主机同时发出 2 个请求。在这种情况下,您有一个服务器应用程序,但没有 ASP.NET 应用程序,因此默认情况下您会启用相当严格的限制。
建议:将此代码放入您的启动中:
ServicePointManager.DefaultConnectionLimit = int.MaxValue;
请注意,.NET Core 默认情况下不会限制客户端 HTTP 请求,因此这只是模拟现代 .NET 平台上的默认行为。
关于c# - 从 HttpClient SendAsync 请求获取响应时出现无法解释的超时和延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67024294/