- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在负责持续解析 HTML 页面的服务器上运行 C# 进程(服务)。它依赖于 HTMLAgilityPack。症状是随着时间的推移越来越慢。
当我启动进程时,它每秒处理 n 页。几个小时后,速度下降到大约 n/2 页/秒。几天后它可以下降到 n/10。这种现象已被多次观察到,而且具有一定的确定性。任何时候重新启动该过程,一切都会恢复正常。
非常重要:我可以在同一个进程中运行其他计算,而且它们不会减慢:我可以随时使用任何我想要的东西来达到 100% 的 CPU。这个过程本身并不慢。只有 HTML 解析变慢。
我可以用最少的代码重现它(实际上原始服务中的行为有点极端,但这段代码仍然重现了该行为):
public static void Main(string[] args) {
string url = "https://en.wikipedia.org/wiki/History_of_Texas_A%26M_University";
string html = new HtmlWeb().Load(url).DocumentNode.OuterHtml;
while (true) {
//Processing
Stopwatch sw = new Stopwatch();
sw.Start();
Parallel.For(0, 10000, i => new HtmlDocument().LoadHtml(html));
sw.Stop();
//Logging
using(var writer = File.AppendText("c:\\parsing.log")) {
string text = DateTime.Now.ToString() + ";" + (int) sw.Elapsed.TotalSeconds;
writer.WriteLine(text);
Console.WriteLine(text);
}
}
}
使用这个最少的代码,它显示速度(每秒页数)作为自进程启动以来经过的小时数的函数:
已排除所有明显原因:
这可能与 RAM 和内存分配有关。我知道 HTMLAgilityPack 进行了大量的小对象内存分配(HTML 节点和字符串)。很明显,内存分配和多线程不能很好地协同工作。但是我不明白这个过程怎么会变得越来越慢。
您是否知道有关 CLR 或 Windows 的任何事情可能会导致某些 RAM 密集型(多次分配)处理变得越来越慢?例如以某种方式惩罚执行内存分配的线程?
最佳答案
我注意到使用 HTMLAgilityPack 时有类似的行为。
我发现,当一个 yield 的数据开始出现空间泄漏时,编译器生成的类中的局部变量开始引起问题。由于没有可用代码,这是我的急救箱。
确保设置 the right strategy ,改变app.config中的GC收集策略将有助于分片。
确保在不需要时将它们清空,一旦不需要它们,不要等待作用域清理内存,因为在调用方法和方法作用域中会调用 IEnumerables变量并且可以比你想象的活得更久!在 ILSpy 中打开您的代码并查看 <>d__0(0) 生成的类。你会看到生成的东西像 d__.X=X;在这种情况下,X 可以包含一个片段或整个页面。
您的局部变量被提升到堆中,因为如果它们不存在,则无法在 IEnumable 迭代中访问它们。
锁定开始成为一个问题,大项目在您的第 4 代 ram 中流血,实际上将开始阻塞 GC。 GC 正在暂停您的线程以执行垃圾收集。
HTMLAgility 最糟糕的地方在于它 fragments that ends up being a real issue
我敢肯定,当您开始考虑 HTML 片段的范围时,您会发现一切都会开始顺利进行。使用 WinDbg in SOS 查看您的执行情况并转储您的内存并查看。
如何做到这一点。
打开 WinDebug,按 F6 并附加到进程(在字段中输入进程 ID,然后按确定)
然后通过输入将执行加载到您的内存中
.loadby sos clr
然后输入
!dumpheap -stat
然后你会得到在你的应用程序中分配的内存项,内存地址和大小按类型分组并从低头到高头排序你会看到类似 System.String[] 的东西,前面有大量数字它,这是您首先要调查的内容。
现在看看谁有你可以输入的内容
!dumpheap -mt <heap address>
您将看到正在使用该内存表 (MT) 的地址及其使用的 ram 的大小。
现在它变得有趣了,而不是你输入 x100 行代码
!gcroot <address>
它将打印的是分配内存的文件和代码行、编译器生成的类和导致您痛苦的变量以及它包含的字节数。
这就是所谓的“生产调试”,如果您可以访问服务器,我想您可以访问它,它就可以工作。
关于c# - 数小时后 RAM 密集型 C# 进程变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50282509/
我有 0 小时、3 小时、12 小时、24 小时、48 小时的数据组……我想绘制这些数据的图表,以便保留时间的比例。 runs <- c(1:25) hours <- as.factor(c(0, 3
例如,如果我选择了时间:下午 3 点和小时数:5 小时,则得到 (8pm) 作为答案“ 最佳答案 let calendar = Calendar.current let date = calendar
我有一个包含两个日期时间字段的表单。用户输入日期 (yyyy-mm-dd) 和时间(3 个框;小时、分钟、上午/下午)。 出于某种原因,第一个没有保存为 24 小时制。 以下数据为输入结果: 2011
我一直在尝试使用导出单位进行计算,但到目前为止我还没有取得任何成果。 我已经尝试过mathjs ,但如果我输入 1 小时 * 1 英里/小时,我会得到 UnsupportedTypeError: Fu
我有两组要运行的 cronjob。第一个应该每 3 小时运行一次,第二个也应该每 3 小时运行一次,但比第一组晚一个小时。什么是正确的语法? // every 3 hours 17 */3 * *
我知道 AWS 中的预留实例更多的是计费而不是实际实例——它们没有附加到实际实例——我想知道: 如果我在特定区域和可用区中购买特定时间的预留实例 - 如果我每天 24 小时使用单个实例与运行 24 个
我试过: seq( from=as.POSIXct("2012-1-1 0", tz="UTC"), to=as.POSIXct("2012-1-3 23", tz="UTC"),
我有一个带有“日期”列的表。我想按小时分组指定日期。 最佳答案 Select TO_CHAR(date,'HH24') from table where date = TO_DATE('2011022
我知道如何在 SQL (SQL Server) 中获取当前日期,但要获取当天的开始时间: select dateadd(DAY, datediff(day, 0, getdate()),0) (res
我正在尝试在游戏之间创建一个计时器,以便用户在失去生命后必须等待 5 分钟才能再次玩游戏。但是我不确定最好的方法是什么。 我还需要它来防止用户在“设置”中编辑他们的时间。 实现这一目标的最佳方法是什么
我的查询有误。该错误显示预期的已知函数,得到“HOUR”。如果我删除这部分,查询将正常工作 (AND HOUR({$nowDate}) = 11) SELECT c FROM ProConvocati
var d1 = new Date(); var d2 = new Date(); d2.setHours(d1.getHours() +01); alert(d2); 这部分没问题。现在我试图在 (
我正在构建一个用于练习的基本时钟应用程序,但出于某种原因,时间不会自动更改为最新的分钟或小时。例如,当前时间是 17:56,但它显示的是 17:54,这是我打开应用程序的最后时间。 NSDate *n
我创建了一张图片,我想将其用作页面的 hr。当它被上传时,它一直向左对齐。我希望它居中,在标题下。这是我的 CSS 代码: .section-underline { height: 35px
这个问题已经有答案了: Getting difference in seconds from two dates in JavaScript (2 个回答) 已关闭 4 年前。 我想计算两个具有不同格
我需要计算到某个日期/时间的剩余时间(天/小时)。 但是,我没有使用静态日期。 假设我在 每个星期日 的 17:00 有一个事件。我需要显示到下一个事件的剩余时间,即即将到来的星期日 17:00。 我
我正在执行这个脚本: SELECT EXTRACT(HOUR FROM TIMEDIFF('2009-12-12 13:13:13', NOW())); 我得到:-838。这是提取时 MySQL 可以
复制代码 代码如下: /** * 小时:分钟的正则表达式检查<br> * <br> * @param pInput 要检查的字符串 * @return boolean 返
连wifi5元/小时 独领风骚 朕好帅 今晚你是我的人 十里桃花 高端定制厕所VP专用 一只老母猪 在家好无聊 你爹的wifi 密码是叫爸爸全拼 关晓彤和鹿晗分手了吗 蹭了我的
我有以下数据框列: 我需要将 csv 列中的对象字符串数据转换为总秒数。 示例:10m -> 600s 我试过这段代码: df.duration = str(datetime.timedelta(df
我是一名优秀的程序员,十分优秀!