- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
小问题:
有没有其他人在使用单例 .NET HttpClient 时遇到问题,其中应用程序将处理器固定在 100%,直到它重新启动?
详情:
我正在运行一个 Windows 服务,该服务执行连续的、基于计划的 ETL。数据同步线程之一偶尔会死掉,或者开始失控并使处理器保持在 100%。
我很幸运在有人简单地重新启动服务(标准修复)并能够获取转储文件之前看到了这种情况。
在 WinDbg(带 SOS 和 SOSEX)中加载它,我发现我有大约 15 个线程(主处理线程的子任务)都以相同的堆栈跟踪运行。但是,似乎没有任何僵局。 IE。高利用率线程正在运行,但从未完成。
相关的堆栈跟踪段如下(地址省略):
System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].FindEntry(System.__Canon)
System.Collections.Generic.Dictionary`2[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].TryGetValue(System.__Canon, System.__Canon ByRef)
System.Net.Http.Headers.HttpHeaders.ContainsParsedValue(System.String, System.Object)
System.Net.Http.Headers.HttpGeneralHeaders.get_TransferEncodingChunked()
System.Net.Http.Headers.HttpGeneralHeaders.AddSpecialsFrom(System.Net.Http.Headers.HttpGeneralHeaders)
System.Net.Http.Headers.HttpRequestHeaders.AddHeaders(System.Net.Http.Headers.HttpHeaders)
System.Net.Http.HttpClient.SendAsync(System.Net.Http.HttpRequestMessage, System.Net.Http.HttpCompletionOption, System.Threading.CancellationToken)
...
[Our Application Code]
根据 this article (和其他我发现的),字典的使用不是线程安全的,如果您以多线程方式访问字典,则可能会出现无限循环(就像直接崩溃一样) .
但是 我们的应用程序代码没有明确使用字典。那么堆栈跟踪中提到的字典在哪里?
通过 .NET Reflector,似乎 HttpClient 使用字典来存储已在“DefaultRequestHeaders”属性中配置的任何值。因此,通过 HttpClient 发送的任何请求都会触发单例非线程安全字典的枚举(以便将默认 header 添加到请求中),这可能会无限地旋转(或杀死)所涉及的线程如果发生腐败。
微软直言HttpClient类是线程安全的。但在我看来,如果任何 header 已添加到 HttpClient 的 DefaultRequestHeaders 中,这就不再成立了。
我的分析似乎表明这是真正的根本问题,一个简单的解决方法是永远不要在可以以多线程方式使用 HttpClient 的地方使用 DefaultRequestHeaders。
但是,我正在寻找一些证据来证明我没有找错树。如果这是正确的,这似乎是 .NET 框架中的错误,我自然而然地倾向于怀疑。
抱歉这个冗长的问题,但感谢您提供的任何意见。
最佳答案
感谢所有评论;他们让我从不同的角度思考问题,并帮助我找到了问题的最终根源。
尽管问题是 DefaultRequestHeaders 支持字典损坏的结果,但真正的罪魁祸首是 HttpClient 对象的初始化代码:
private HttpClient InitializeClient()
{
if (_client == null)
{
_client = GetHttpClient();
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
SetBaseAddress(BaseAddress);
}
return _client;
}
我说 HttpClient 是一个单例,这是部分不正确的。它是作为单个实例创建的,在执行一个工作单元的多个线程之间共享,并在工作完成时被释放。下次必须完成此特定任务时,将启动一个新实例。
上面的“InitializeClient”方法在每次发送请求时都会被调用,并且应该只是因为“_client”字段在第一次运行后不为空而短路。
(请注意,这不是在对象的构造函数中完成的,因为它是一个抽象类,而“GetHttpClient”是一个抽象方法——顺便说一句:永远不要在基类的构造函数中调用抽象方法。 .这会导致其他噩梦)
当然,很明显这不是线程安全的,并且由此产生的行为是不确定的。
解决方法是将此代码放在经过双重检查的“锁定”语句后面(尽管我无论如何都会消除对“DefaultRequestHeaders”属性的使用,只是因为)。
简而言之,如果您在初始化 HttpClient 时小心谨慎,我最初的问题就不会成为问题。
感谢你们提供的思路清晰!
关于c# - .NET:由于字典,HttpClient 中的 CPU 使用率为 100%?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36774293/
我看到很多人发布关于 NullInjectorError: No provider for HttpClient! 的问题但是我在 Karma 单元测试中遇到了更具描述性的错误。我一直在学习 Angu
全部, 我创造: public static final HttpClient DEFAULT_HTTPCLIENT = HttpClients .createDefault(); f
我正在使用 HttpClient fluent api 编写验收测试,但遇到了一些麻烦。 @When("^I submit delivery address and delivery time$")
有人可以分享如何配置现代 HttpClient 4.5.3 以重试失败的请求并在每次重试前等待一段时间吗? 到目前为止,我似乎正确理解了 .setRetryHandler(new DefaultHtt
我在使用 java 中的 HttpClient 库时遇到问题。 目标网站在 SSL ( https://www.betcris.com ) 上,我可以从该网站加载索引页面就好了。 但是,显示不同运动赔
所以我的应用涉及大量网络调用(可能连接到 10 个不同的服务器)和获取数据。从我读过的几篇文章中,建议重用 HTTPClient 实例,因为它可以防止资源(套接字等)的浪费。但是我发现围绕可扩展且健壮
我正在调用一个外部 API,并希望我的 API 可以进行单元测试。为此,我正在尝试包装 HttpClient。我现在只需要一种方法。 这是我的界面。 public interface IHttpCli
出于调试目的,我希望看到将要发送的原始请求。有没有一种方法可以直接从 HttpPost 或 HttpClient 的API中获得没有HTTP监视器的信息? 我发现了一些“几乎”重复的问题,但不是针对这
我正在尝试在小型 WebAssemply 应用程序(使用 .NET 5 创建)中测试 HttpClient。program.cs 包含以下语句来添加 HttpClient 服务: builder.Se
我在 Application_Start 事件中创建了 HttpClient 的单个实例,以便在 Global.asax.cs 中的应用程序中重用 应用程序启动中的代码: protected
我对此有点新手...基本上我需要运行一个脚本来从谷歌趋势下载.csv 文件。我按照这个reference写了下面的代码,代码如下: HttpClient client = new Defau
我正在尝试实现一个基本的 1 spout - 1 bolt Storm 拓扑。我有一个 Storm Bolt,可以使用 Apache HttpClient (4.3.1) 发出 HTTP 请求。但是,
我正在尝试在我的 Xamarin.Forms 移动应用程序中使用 HttpClient 创建网络服务层。 没有单例模式 单例模式 在第一种方法中,我在每个新请求中创建新的 http 客户端对象通过移动
在下面的示例中,我创建了一个 Java 11 httpClient,然后创建了多个并发 HttpRequest。 这是不好的做法吗? 每个 HttpRequest 都应该有自己的 HttpClient
我正在开发一个 Drupal 8 自定义模块。我在任何节点类型中都有两个字段(url 和文本 html 字段)。这是该模块所期望的功能: 该模块将抓取“url字段”的页面并复制html代码以将它们粘贴
我正在为 httpclient 使用 apache httpcompnonents 库。我想在多线程应用程序中使用它,其中线程数会非常高,并且会有频繁的 http 调用。这是我用来在执行调用后读取响应
最近我将我的代码库从 .net core 1.0 迁移到 2.0 。之后,我随机收到错误 “使用 System.Net.Http.HttpClient 时服务器返回无效或无法识别的响应错误”。我在 1
我有该代码: while(!lastPage && currentPage < maxPageSize){ StringBuilder request = new Strin
我的应用程序使用 Apache HTTPClient 4.3.5 发送 HTTP 请求并获得响应。 我想弄清楚应用程序收到了什么响应。 以下是日志片段- [Jan 04 2015 05:38:14.1
如何从 HttpClient 类型的现有对象获取 cookie? 我正在使用 HttpClient 版本 4.3.3,它不再有方法 httpClient.getCookieStore() 了。 最佳答
我是一名优秀的程序员,十分优秀!