【问题标题】:What is the fastest way to read 10 GB file from the disk?从磁盘读取 10 GB 文件的最快方法是什么?
【发布时间】:2009-08-28 22:03:40
【问题描述】:

我们需要读取和统计不同类型的消息/运行 10 GB 文本文件的一些统计信息,例如 FIX 引擎 日志。我们使用 Linux,32 位,4 个 CPU,Intel,用 Perl 编码,但是 语言并不重要。

我在 Tim Bray 的文章中发现了一些有趣的提示 WideFinder project。但是,我们发现使用内存映射 本质上受 32 位架构的限制。

我们尝试使用多个进程,这似乎可行 如果我们使用 4 个进程并行处理文件,速度会更快 在 4 个 CPU 上。添加多线程可能会减慢它的速度 因为上下文切换的成本。我们尝试改变 线程池的大小,但这仍然比 简单的多进程版本。

内存映射部分不是很稳定,有时候会 2 GB 文件需要 80 秒,有时需要 7 秒,可能来自 页面错误或与虚拟内存使用有关的东西。 无论如何,Mmap 不能在 32 位上扩展超过 4 GB 架构。

我们尝试了 Perl 的 IPC::MmapSys::Mmap。看着 也进入 Map-Reduce,但问题实际上是 I/O 绑定,处理本身就足够快了。

所以我们决定尝试通过调优来优化基本 I/O 缓冲大小、类型等

任何了解现有项目的人都可以 问题在任何语言/平台上都得到了有效解决 指向一个有用的链接或建议一个方向?

【问题讨论】:

  • 2G单cpu的原始性能是多少?您可能需要确定是 I/O 问题还是 CPU 计算问题。
  • 如果您真的受磁盘 (IO) 限制,那么最好的方法可能是购买更快的磁盘、更多的磁盘(在 RAID0、RAID5、RAID10 等中)或 64 位机器足够的内存将文件存储在 RAM 磁盘上。任何合理的单盘都应该能拉50MB/秒;多个快速磁盘应该能够将您推到至少 300MB/秒。
  • 我建议您不要使用 Sys::Mmap 而是使用 File-Map(原因在后者的文档中说明)。无论如何,您可能不想使用 IPC::Mmap。

标签: perl io mmap performance


【解决方案1】:

大多数情况下,您将受到 I/O 限制而不是 CPU 限制,因此只需通过普通 Perl I/O 读取此文件并在单线程中处理它。除非你证明你可以做比你的单个 CPU 工作更多的 I/O,否则不要在任何事情上浪费你的时间。无论如何,你应该问:为什么这在一个巨大的文件中?为什么他们在生成它时不以合理的方式拆分它?这将是更有价值的工作。然后你可以把它放在单独的 I/O 通道中并使用更多的 CPU(如果你不使用某种 RAID 0 或NAS 或...)。

衡量,不要假设。不要忘记在每次测试之前刷新缓存。请记住,序列化 I/O 比随机 I/O 快一个数量级。

【讨论】:

    【解决方案2】:

    这一切都取决于您可以进行何种预处理以及何时进行。 在我们拥有的一些系统上,我们会压缩如此大的文本文件,将它们缩小到原始大小的 1/5 到 1/7。使这成为可能的部分原因是我们不需要处理这些文件 直到它们被创建几个小时后,在创建时我们实际上并没有任何其他负载在机器上。

    处理它们或多或少以 zcat thosefiles | 的方式完成。我们的处理。(虽然使用定制的 zcat,但它是通过 unix 套接字完成的)。它用 cpu 时间换取磁盘 i/o 时间,换取我们的系统,非常值得。当然,对于特定系统来说,有很多变数可能会导致这种设计非常糟糕。

    【讨论】:

      【解决方案3】:

      也许您已经阅读过这个论坛帖子,但如果没有:

      http://www.perlmonks.org/?node_id=512221

      它描述了使用 Perl 逐行执行,用户似乎认为 Perl 非常有能力。

      哦,可以处理来自 RAID 阵列的文件吗?如果您有多个镜像磁盘,则可以提高读取速度。磁盘资源的竞争可能是导致您的多线程尝试不起作用的原因。

      祝你好运。

      【讨论】:

        【解决方案4】:

        我希望我能更多地了解您的文件的内容,但不知道它是文本,这听起来像是一个极好的 MapReduce 问题。

        PS,任何文件的最快读取都是线性读取。 cat file > /dev/null应该是可以读取文件的速度。

        【讨论】:

        • 确实;我的同事正在研究类似的问题,他使用 cat 的时间来追踪文件读取速度方面的其他问题。 NFS 真是太糟糕了。 :(
        【解决方案5】:

        您是否考虑过流式传输文件并将任何有趣的结果过滤到辅助文件中? (重复直到你有一个可管理大小的文件)。

        【讨论】:

          【解决方案6】:

          基本上需要“分而治之”,如果你有电脑网络,那么将10G的文件复制到尽可能多的客户端PC上,让每台客户端PC读取文件的偏移量。为了额外的好处,除了分布式读取之外,让每台电脑实现多线程。

          【讨论】:

          • "问题确实是 IO 限制"
          【解决方案7】:

          解析文件一次,逐行读取。将结果放在一个像样的数据库中的表中。运行任意数量的查询。定期向野兽提供新的传入数据。

          意识到处理 10 Gb 文件、通过(即使是本地)网络传输文件、探索复杂的解决方案等都需要时间。

          【讨论】:

          • Feed 数据库和运行查询可能比 perl 中的所有处理花费更多的时间。 (根据我的经验,即使您使用批量加载和 MySQL,这是您可以使用的最快方法之一。)
          • 一旦您在 decent 数据库中获得了数据,您可以运行任意数量的查询(即使是那些您不知道您可能想要运行的查询)额外费用。
          【解决方案8】:

          我有一位同事通过使用 64 位 Linux 来加快他的 FIX 阅读速度。如果值得的话,花一点钱买一些更高级的硬件。

          【讨论】:

            【解决方案9】:

            hmmm,但是 C 中的 read() 命令有什么问题?通常有2GB的限制, 所以只需依次调用它 5 次。那应该相当快。

            【讨论】:

              【解决方案10】:

              如果您受 I/O 限制,并且您的文件位于单个磁盘上,那么就没有什么可做的了。对整个文件进行简单的单线程线性扫描是从磁盘中获取数据的最快方法。使用较大的缓冲区大小可能会有所帮助。

              如果您可以说服文件的编写者将其跨多个磁盘/机器进行条带化,那么您可以考虑对读取器进行多线程处理(每个读取头一个线程,每个线程从单个条带中读取数据)。

              【讨论】:

                【解决方案11】:

                既然你说平台和语言无关紧要......

                如果您想要在源媒体允许的情况下尽可能快地获得稳定的性能,我知道在 Windows 上可以做到这一点的唯一方法是通过重叠的非操作系统缓冲对齐顺序读取。您可能可以使用两个或三个缓冲区达到一些 GB/s,除此之外,在某些时候您需要一个环形缓冲区(一个写入器,1 个以上读取器)以避免任何复制。确切的实现取决于驱动程序/API。如果在处理 IO 的线程(包括内核模式和用户模式)上有任何内存复制,显然要复制的缓冲区越大,浪费的时间就越多,而不是执行 IO。因此最佳缓冲区大小取决于固件和驱动程序。在 Windows 上,要尝试的好值是磁盘 IO 的 32 KB 的倍数。 Windows 文件缓冲、内存映射和所有这些东西都会增加开销。仅在以随机访问方式对相同数据进行多次读取(或两者)时才有用。因此,对于一次按顺序读取大文件,您不希望操作系统缓冲任何内容或执行任何 memcpy。如果使用 C#,由于编组,调用操作系统也会受到惩罚,因此互操作代码可能需要一些优化,除非您使用 C++/CLI。

                有些人更喜欢用硬件来解决问题,但如果您的时间多于金钱,那么在某些情况下,有可能对事情进行优化,使其在单台消费级计算机上的性能比 1000 台企业级计算机的性能好 100-1000 倍。原因是如果处理也对延迟敏感,那么使用两个内核可能会增加延迟。这就是为什么驱动程序可以推动千兆字节/秒,而企业软件在全部完成时最终停留在兆字节/秒。无论报告、业务逻辑和此类企业软件做什么,都可能在两个核心消费者 CPU 上以千兆字节/秒的速度完成,如果你像 80 年代写游戏那样编写的话。我听说过以这种方式处理他们的整个业务逻辑的最著名的例子是 LMAX 外汇交易所,它发布了一些基于环形缓冲区的代码,据说是受到网卡驱动程序的启发。

                忘记所有理论,如果您对

                【讨论】:

                  【解决方案12】:

                  我似乎记得一个我们正在读取大文件的项目,我们的实现使用了多线程 - 基本上 n * worker_threads 开始于增加文件的偏移量(0,chunk_size,2xchunk_size,3x chunk_size ... n-1x chunk_size ) 并且正在读取较小的信息块。我无法完全回忆起我们这样做的原因,因为其他人正在设计整个事情 - 工人并不是唯一的事情,但我们大致就是这样做的。

                  希望对你有帮助

                  【讨论】:

                    【解决方案13】:

                    问题中没有说明顺序是否重要。所以, 将文件分成相等的部分,每个 1GB,由于您使用多个 CPU,因此多个线程不会成为问题,因此使用单独的线程读取每个文件,并使用容量 > 10 GB 的 RAM,然后您的所有内容都将被存储在被多个线程读取的 RAM 中。

                    【讨论】:

                      猜你喜欢
                      • 2015-05-29
                      • 2010-11-08
                      • 2011-02-02
                      • 1970-01-01
                      • 2021-12-08
                      • 1970-01-01
                      • 1970-01-01
                      • 2018-04-29
                      • 2013-10-24
                      相关资源
                      最近更新 更多