代码之家  ›  专栏  ›  技术社区  ›  alex

从磁盘读取10 GB文件的最快方法是什么?

  •  11
  • alex  · 技术社区  · 15 年前

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

    我在蒂姆·布雷的书里发现了一些有趣的提示 WideFinder project . 但是,我们发现使用内存映射 本质上受到32位体系结构的限制。

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

    内存映射部分不太稳定,有时 在一个2 GB文件上需要80秒有时7秒,可能来自 页面错误或与虚拟内存使用有关的内容。 无论如何,mmap不能在32位上扩展到4 GB以上 建筑学。

    我们尝试了Perl IPC::Mmap Sys::Mmap . 看 into map也减少了,但问题是真正的I/O 当然,处理本身足够快。

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

    任何人知道一个现有的项目 任何语言/平台都能有效解决问题 指向有用的链接或建议方向?

    13 回复  |  直到 15 年前
        1
  •  9
  •   Peter Mortensen sifr_dot_in    15 年前

    大多数时候,您将被I/O绑定,而不是CPU绑定,因此只需通过普通的Perl I/O读取这个文件并在单线程中处理它。除非你证明你可以做比你的单CPU工作更多的I/O,否则不要把你的时间浪费在更多的事情上。不管怎样,你应该问:为什么这是一个巨大的文件?为什么在地球上,当它们产生它的时候,它们不以一种合理的方式把它分开呢?这将是规模更值得工作。然后,您可以将它放在单独的I/O通道中,并使用更多的CPU(如果您不使用某种类型的RAID 0或 NAS 或者……)

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

        2
  •  4
  •   nos    15 年前

    这完全取决于你能做什么样的预处理以及什么时候做。 在我们拥有的一些系统上,我们gzip这样大的文本文件,将它们减少到原始大小的1/5到1/7。使这成为可能的部分原因是我们不需要处理这些文件 在它们被创建后的几个小时内,在创建时,我们在机器上没有任何其他负载。

    处理它们或多或少是以zcat thosefiles ourprocessing的方式完成的(虽然它是通过一个定制的zcat在Unix套接字上完成的)。它将CPU时间与磁盘I/O时间以及 值得的。当然,对于一个特定的系统,有很多变量可以使它成为一个非常糟糕的设计。

        3
  •  3
  •   Jon Onstott    15 年前

    也许你已经阅读过这个论坛的主题,但如果没有:

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

    它描述了使用Perl一行一行地完成它,并且用户似乎认为Perl非常有能力做到这一点。

    哦,是否可以从RAID阵列处理该文件?如果您有几个镜像磁盘,那么可以提高读取速度。对磁盘资源的竞争可能会使多线程无法工作。

    祝你好运。

        4
  •  3
  •   Jeff Ferland    15 年前

    我希望我知道更多关于您的文件内容,但不知道除了它是文本以外,这听起来像是一个优秀的MapReduce类型的问题。

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

        5
  •  2
  •   Paul Nathan    15 年前

    您是否想过将文件流式处理并筛选到辅助文件中,有什么有趣的结果?(重复,直到有一个可管理的大小文件)。

        6
  •  1
  •   Darknight    15 年前

    基本上需要“分而治之”,如果你有一个计算机网络,然后把10g文件复制到尽可能多的客户机上,让每个客户机读取文件的偏移量。为了增加额外的奖励,让每台PC除了分布式读取外,还实现多线程。

        7
  •  1
  •   Sinan Ünür    15 年前

    分析文件一次,逐行读取。将结果放入一个合适的数据库中的表中。运行任意多的查询。定期向Beast提供新的传入数据。

    意识到操作一个10 GB的文件、在(即使是本地的)网络上传输它、探索复杂的解决方案等都需要时间。

        8
  •  1
  •   brian d foy    15 年前

    我有一个同事,他通过使用64位Linux加快了修复速度。如果有什么值得的话,可以花点钱买些更高级的硬件。

        9
  •  1
  •   tsukasa    15 年前

    嗯,但是C中的read()命令有什么问题?通常有2GB的限制, 所以按顺序打5次。那应该相当快。

        10
  •  1
  •   Keith Randall    15 年前

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

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

        11
  •  1
  •   Anonymous Coward    11 年前

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

    如果您想要一个与源媒体允许的速度一样快的稳定性能,我知道在Windows上实现这一点的唯一方法就是通过重叠的非操作系统缓冲对齐顺序读取。除此之外,您可能还需要一个环形缓冲区(一个编写器,1个以上的读卡器)来避免任何复制。具体的实现取决于驱动程序/API。如果在处理IO的线程上(在内核和用户模式下)进行了内存复制,那么显然要复制的缓冲区越大,就浪费的时间越多,而不是执行IO。因此,最佳缓冲区大小取决于固件和驱动程序。在Windows上,要尝试的好值是磁盘IO的32 KB的倍数。Windows文件缓冲、内存映射以及所有这些都会增加开销。只有在以随机访问方式对同一数据进行多次(或同时进行)读取时才是好的。因此,对于一个单一的时间顺序读取大文件,您不希望OS缓冲任何东西或做任何MimcPy。如果使用C ^,由于封送处理,也会调用到OS中的惩罚,所以互操作代码可能需要优化,除非您使用C++/CLI。

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

    忘记所有的理论,如果您对<1 GB/s满意,我在Windows上发现的一个可能的起点是从winimage查找readfile源,除非您想深入了解sdk/驱动程序示例。它可能需要一些源代码修复来正确计算SSD速度下的性能。还可以对缓冲区大小进行试验。 根据我的经验,使用无Windows文件缓冲的/h多线程和/o重叠(完成端口)IO和最佳缓冲区大小(尝试32,64128 kb等),在同时处理(使用/a进行Adler处理,否则它太受CPU限制)的同时,从SSD(冷数据)读取时性能最佳。

        12
  •  0
  •   Maciek    15 年前

    我好像还记得一个项目,在这个项目中我们读取大文件,我们的实现使用多线程——基本上,n*工作线程从文件的偏移量开始递增(0,chunk_size,2xchunk_size,3x chunk_size…n-1X块大小),正在读取较小的信息块。我无法准确地回忆起我们对这件事的推理,因为其他人正在停止整件事——工人并不是唯一的事情,但我们就是这样做的。

    希望它有帮助

        13
  •  0
  •   pokrate    15 年前

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