12

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

我在 Tim Bray 的 WideFinder 项目中发现了一些有趣的技巧。但是,我们发现使用内存映射本质上受到 32 位架构的限制。

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

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

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

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

任何知道在任何语言/平台上有效解决此问题的现有项目的人都可以指出有用的链接或建议方向吗?

4

13 回答 13

9

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

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

于 2009-08-29T22:23:32.587 回答
4

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

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

于 2009-08-29T21:29:41.197 回答
3

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

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

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

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

祝你好运。

于 2009-08-28T22:25:25.280 回答
3

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

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

于 2009-08-28T22:44:02.120 回答
2

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

于 2009-08-28T22:20:21.373 回答
1

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

于 2009-08-28T22:51:05.600 回答
1

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

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

于 2009-08-29T13:37:40.983 回答
1

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

于 2009-08-29T21:21:27.610 回答
1

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

于 2009-09-23T04:25:34.640 回答
1

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

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

于 2009-09-28T21:23:26.297 回答
1

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

If you want a stable performance that is as fast as the source medium allows for, the only way I am aware that this can be done on Windows is by overlapped non-OS-buffered aligned sequential reads. You can probably get to some GB/s with two or three buffers, beyond that, at some point you need a ring buffer (one writer, 1+ readers) to avoid any copying. The exact implementation depends on the driver/APIs. If there's any memory copying going on the thread (both in kernel and usermode) dealing with the IO, obviously the larger buffer is to copy, the more time is wasted on that rather than doing the IO. So the optimal buffer size depends on the firmware and driver. On windows good values to try are multiples of 32 KB for disk IO. Windows file buffering, memory mapping and all that stuff adds overhead. Only good if doing either (or both) multiple reads of same data in random access manner. So for reading a large file sequentially a single time, you don't want the OS to buffer anything or do any memcpy's. If using C# there's also penalties for calling into the OS due to marshaling, so the interop code may need bit of optimization unless you use C++/CLI.

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

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

于 2013-12-16T07:59:23.487 回答
0

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

希望能帮助到你

于 2009-08-28T22:17:33.890 回答
0

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

于 2009-10-12T18:04:30.680 回答