我们有一个 .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)
我还想也许我遇到了等待/异步和 .Result 的死锁情况,但死锁意味着请求永远不会完成,而不是它会延迟 10 秒。
我还仔细检查过我们只使用了一个 httpclient 实例,而且确实如此。
还能是什么?
此时,我们正在删除 .Result 并将其替换为适当的 async/await。但我没有证据表明这会解决问题,因为我没有看到任何死锁或线程耗尽的证据。
Here is a perfview analysis
我们还在研究有关我们正在以某种方式耗尽 http 连接的建议。我认为情况并非如此的原因之一是,根据 perfview,请求正在发送并且数据包返回,但响应并没有组成 c# 堆栈。然而,这些性能计数器可能表明存在一些排队现象。
Update我们已经增加了http连接,它似乎生效了。
<connectionManagement>
<add address="*" maxconnection="1024"/>
</connectionManagement>
上面显示的排队完全消失了。然而,这些请求未完成的问题仍然存在