c# - 从 HttpClient SendAsync 请求获取响应时出现无法解释的超时和延迟

标签 c# async-await threadpool dotnet-httpclient

我们有一个 .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。但我没有证据表明这会解决问题,因为我没有看到任何死锁或线程耗尽的证据。

这是一个性能 View 分析 enter image description here

我们还在研究有关我们正在以某种方式耗尽 http 连接的建议。我认为情况并非如此的原因之一是,根据 perfview,请求正在发送并且数据包返回,但响应并没有组成 c# 堆栈。然而,这些性能计数器可能表明存在一些排队现象。

enter image description here

更新 我们已经增加了 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/

相关文章:

javascript - 使用 puppeteer 等待 fs writefile 不会等到文件写入后再继续事件循环

.net-4.5 - 异步 - 留在当前线程上?

mysql - Node.js:如何以最简单的方式将 util.promisify 应用于 mysql 池?

python - 当我尝试通过multiprocess.Pool在python中加速程序时,为什么多进程比单进程慢?

java - Apache + Tomcat部署中Tomcat线程池的行为

java - 多个线程修改相同的命令属性

c# - 使用 Razor 的 Html.FormatValue 中的粗体文本

继承属性类的 c# OO 建议

c# - 使用来自对象的参数格式化字符串

c# - 如何使窗口高度适应内容?