FileStream在应用程序冷启动时非常慢

时间:2009-11-02 20:35:28

标签: c# .net windows performance hard-drive

如果您感兴趣,也会问here on SO一个非常相似的问题,但正如我们将会看到该问题的接受答案并非总是如此(我的申请使用模式从来都不是这样) )。

性能确定代码由FileStream构造函数(用于打开文件)和SHA1哈希(.Net框架实现)组成。代码几乎是我在上面链接的问题中提到的C#版本。

案例1:应用程序首次启动或第N次启动,但设置的目标文件不同。现在告诉应用程序计算之前从未访问过的文件的哈希值。

  • 50ms的〜
  • 80%FileStream构造函数
  • 18%哈希计算

案例2:应用程序现已完全终止,并再次启动,要求计算相同文件的哈希值:

  • 〜8ms的
  • 90%哈希计算
  • 8%FileStream构造函数

问题
我的应用程序一直在使用案例1 。永远不会要求它重新计算已经访问过一次的文件的哈希值。

所以我的速率决定步骤是FileStream Constructor!有什么办法可以加速这个用例吗?

谢谢。

P.S。使用JetBrains分析器收集统计数据。

5 个答案:

答案 0 :(得分:3)

  

...但目标文件集不同。

关键词,您的应用程序将无法利用文件系统缓存。就像第二次测量一样。目录信息不能从RAM中获取,因为还没有被读取,操作系统总是不得不退回到磁盘驱动器上,而且速度很慢。

只有更好的硬件才能加快速度。 50毫秒大约是主轴驱动器所需的标准时间,而20毫秒大约是这种驱动器可以使用的时间。读者头的搜寻时间是硬性的机械限制。今天,这很容易克服,SSD广泛可用并且价格合理。唯一的问题是,当您习惯了它之后,便再也不会后退了:)

答案 1 :(得分:1)

文件系统和/或磁盘控制器将缓存最近访问的文件/扇区。

速率确定步骤是读取文件,而不是构造FileStream对象,并且当数据在缓存中时,第二次运行时速度会明显加快,这是完全正常的。

答案 2 :(得分:1)

如前所述,文件系统具有自己的缓存机制,会干扰您的测量。

但是,const tryParseBoolean = value => { if (value === 'true') { return true } if (value === 'false') { return false } return value } const formEntriesToJson = entries => { const data = {} for (const [key, val] of entries) { data[key] = tryParseBoolean(val) } return data } 构造函数执行几个任务,这些任务第一次很昂贵,并且需要访问文件系统(因此某些内容可能不在数据缓存中)。出于说明性的原因,您可以看一下代码,并看到FileStream类用于检测子要素的使用。与该类一起,Reflection被直接(用于访问当前程序集)和间接(对于CAS保护的部分,安全链接要求)大量使用。反射引擎拥有自己的缓存,并且在其缓存为空时需要访问文件系统。

两个测量值是如此不同,感觉有点奇怪。当前,我们的计算机上配备了配置了实时防护的防病毒软件,具有类似的功能。在这种情况下,防病毒软件位于中间,并且缓存的首次访问或丢失取决于该软件的实现。

由于已知的解码漏洞,防病毒软件可能会决定主动检查某些图像文件,例如PNG。这样的检查会导致额外的速度降低,并占​​用最外层.NET类(即CompatibilitySwitches类)中的时间。

使用本机符号和/或内核调试进行分析,应该可以为您提供更多见识。

根据我的经验,您无法描述您所描述的内容,因为我们无法控制多个隐藏层。根据您的用法(目前尚不十分清楚),您可以将应用程序置于服务中,因此可以更快地处理所有后续请求。或者,您可以将多个请求批量处理到一个调用中,以实现摊销的成本降低。

答案 3 :(得分:1)

偏离轨道的建议,但这是我做了很多事情,使我们的分析速度提高了30%-70%:

  

缓存


编写另一段代码,将:

  • 遍历所有文件;
  • 计算哈希;并且,
  • 将其存储在另一个 index 文件中。

现在,在应用程序启动时,不要调用FileStream构造函数来计算哈希。相反,请打开(可能大得多)较小的索引文件,并从中读取预先计算的哈希值。

此外,如果这些文件是在每次启动应用程序之前重新创建的日志等文件,请在文件创建器中添加代码,以使用新创建的文件的哈希值更新索引文件。

这样,您的应用程序始终只能从索引文件中读取哈希。


我同意@HansPassant关于使用SSD来提高磁盘读取速度的建议。这个答案和他的答案是免费的。您可以同时实现这两者以最大化性能。

答案 4 :(得分:-1)

您应该尝试使用原生FILE_FLAG_SEQUENTIAL_SCAN,您必须按CreateFile进行操作才能获得处理并将其传递给FileStream