代码之家  ›  专栏  ›  技术社区  ›  Alex K

文件流在应用程序冷启动时非常慢

  •  10
  • Alex K  · 技术社区  · 16 年前

    也有人提出了一个非常类似的问题 here on SO 如果您感兴趣,但正如我们将看到的那样,这个问题的公认答案并不总是这样(而且我的应用程序使用模式也从来不是这样)。

    性能决定代码由文件流构造函数(打开文件)和sha1哈希(.net framework实现)组成。在我上面提到的问题中,代码是非常复杂的。

    案例1: 应用程序第一次或第n次启动,但目标文件集不同。应用程序现在被告知要计算以前从未访问过的文件的哈希值。

    • ~50毫秒
    • 80%文件流构造函数
    • 18%哈希计算

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

    • ~8ms
    • 90%哈希计算
    • 8%文件流构造函数

    问题
    我的申请书一直在用 案例1 . 它永远不会被要求重新计算已经访问过一次的文件上的哈希值。

    所以我的速率决定步骤是文件流构造函数!我能做些什么来加速这个用例吗?

    谢谢您。

    P.S.的数据是用喷气式飞机剖面仪收集的。

    5 回复  |  直到 7 年前
        1
  •  3
  •   Hans Passant    7 年前

    …但目标文件集不同。

    关键短语,您的应用程序将无法利用文件系统缓存。就像第二次测量一样。目录信息不能来自RAM,因为它还没有被读取,操作系统总是必须回落到磁盘驱动器,这是缓慢的。

    只有更好的硬件才能加快速度。50毫秒是主轴驱动所需的标准时间量,20毫秒大约是这样的驱动器可以去。读头寻道时间是硬机械极限。这很容易击败今天,固态硬盘是广泛可用和合理的负担得起。唯一的问题是,当你习惯了它,你就再也不会后退:)

        2
  •  1
  •   scharette    7 年前

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

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

        3
  •  1
  •   displayName    7 年前

    偏离轨道的建议,但这是我做了很多工作,我们的分析速度加快了30%-70%:

    高速缓存


    再写一段代码:

    • 遍历所有文件;
    • 计算散列;并且,
    • 储存在另一个 指数 文件。

    现在,不要打电话给 FileStream 构造函数在应用程序启动时计算哈希。相反,打开(预期要小得多)的索引文件并读取它的预计算散列。

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

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


    我同意@hanspassant关于使用ssd使磁盘读取更快的建议。这个答案和他的答案是恭维的。可以实现两者最大化性能。

        4
  •  1
  •   Jason Aller    7 年前

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

    然而, FileStream 构造函数执行多个任务,这些任务第一次开销很大,需要访问文件系统(因此可能不在数据缓存中)。出于解释的原因,您可以查看代码,并查看 CompatibilitySwitches 类用于检测子特征的使用。与这个类一起,反射被大量使用直接(访问当前程序集)和间接地(对于CAS受保护的部分,安全链路需求)。反射引擎有自己的缓存,当自己的缓存为空时需要访问文件系统。

    感觉有点奇怪,这两个测量值是如此不同。目前,我们的机器上也有类似的配置了实时保护的防病毒软件。在这种情况下,防病毒软件处于中间,缓存在第一次被命中或错过时,这取决于此类软件的实现。

    由于已知的解码漏洞,防病毒软件可能决定积极检查某些图像文件,如PNG。这种检查会带来额外的减速,并在最外层的.net类中计算时间,即 文件流 班级。

    使用本机符号和/或内核调试进行分析,应该会给您更多的洞察力。

    根据我的经验,你所描述的无法减轻,因为我们无法控制多个隐藏层。根据您的使用情况(我现在还不完全清楚),您可以在服务中打开应用程序,因此您可以更快地处理所有后续请求。另外,您可以将多个请求批处理到一个调用中,以实现分摊的降低成本。

        5
  •  -1
  •   Shay Erlichmen    16 年前

    你应该试着用本地的 FILE_FLAG_SEQUENTIAL_SCAN ,你将不得不去品沃克 CreateFile 为了得到一个把手并把它传给 FileStream