我有一个Linux应用程序,可以并行读取150-200个文件(4-10 in )。每个文件依次读取大小可变的小数据块,每个数据块通常小于2K。
我当前需要保持超过200 MB/s的文件组合读取速率。磁盘可以很好地处理这一点。预计会有超过1 GB/s的需求(目前该磁盘无法访问)。
我们实现了两个不同的读取系统,都大量使用了posix_advise:第一个是mmaped读取,我们映射整个数据集并按需读取。第二种是基于read()/seek()的系统。
这两种方法都工作得很好,但仅适用于中等大小的情况,read()方法可以更好地管理我们的整体文件缓存,可以很好地处理100 GB的文件,但受到严重的速率限制,mmap能够预缓存数据,使超过200MB/s的持续数据速率易于维护,但不能处理大型总数据集大小。
所以我的问题来了:
答:除了Linux上的posix_advise调用,或者已经调优了磁盘调度器、VMM和posix_advise调用之后,read()类型的文件i/o还能得到进一步的优化吗?
B: mmap有没有系统的方法来更好地处理非常大的映射数据?
Mmap-vs-reading-blocks是一个类似于我正在工作的问题,并为这个问题提供了一个很好的起点,以及在mmap-vs-read中的讨论。
发布于 2011-11-09 05:26:30
回溯到什么?此数据的最终目的地是什么?
由于听起来您完全受IO限制,因此mmap和read应该没有区别。有趣的部分在于如何将数据发送到接收器。
假设您将这些数据放到管道中,我建议您只将每个文件的内容全部转储到管道中。要使用零拷贝完成此操作,请尝试使用splice系统调用。您还可以尝试手动复制文件,或者派生一个cat实例或其他一些工具,这些工具可以将当前文件作为标准输入和管道作为标准输出进行大量缓冲。
if (pid = fork()) {
waitpid(pid, ...);
} else {
dup2(dest, 1);
dup2(source, 0);
execlp("cat", "cat");
}Update0
如果您的处理是与文件无关的,并且不需要随机访问,那么您希望使用上面列出的选项创建一个管道。您的处理步骤应该接受来自stdin或管道的数据。
要回答您更具体的问题:
Linux A:除了posix_advise调用之外,read()类型的文件i/o还能进一步优化吗?或者已经调优了磁盘调度器、
和posix_advise调用,是不是像我们预期的那样好?
对于告诉内核从用户空间做什么,这就是最好的结果。剩下的由你决定:缓冲,线程等等,但这是危险的,而且可能是徒劳无益的猜测工作。我只需要将文件拼接到管道中即可。
B: mmap有没有系统的方法来更好地处理非常大的映射数据?
是。following options可能会给你带来惊人的性能优势(通过测试,可能会让mmap变得值得使用):
MAP_HUGETLB使用“巨型页面”来分配映射。这将减少内核中的分页开销,如果您将映射千兆字节大小的files.
MAP_NORESERVE,这将是非常好的。不要为此映射保留交换空间。当交换空间被保留时,可以保证可以修改映射。当交换空间未保留时,如果没有可用的物理内存,则可能会在写入时获得SIGSEGV。如果您实际上没有足够的物理内存+交换空间用于映射的整个mapping.**
MAP_POPULATE填充(预错)页面表,这将防止您耗尽内存,同时保持实现简单。对于文件映射,这会导致对文件进行预读。以后对映射的访问将不会因为页面错误而被阻止。如果预取是有序的,并且是惰性的,这可能会在有足够的硬件资源的情况下给你加速。我怀疑这个标志是多余的,默认情况下VFS可能做得更好。
发布于 2011-11-09 05:04:36
也许使用readahead系统调用可能会有所帮助,如果您的程序可以提前预测它想要读取的文件片段(但这只是一个猜测,我可能是错的)。
我认为你应该调整你的应用程序,甚至你的算法,以读取比几千字节大得多的数据块。不能只有半兆字节吗?
发布于 2011-11-09 05:23:24
这里的问题似乎不在于使用了哪种api。不管你是使用mmap()还是read(),磁盘仍然需要找到指定的点并读取数据(尽管操作系统确实有助于优化访问)。
如果读取非常小的块(几个字节),mmap()比read()更有优势,因为您不必为每个块调用os,这会变得非常慢。
我还建议像Basile那样连续读取超过2kb的内容,这样光盘就不需要经常查找了。
https://stackoverflow.com/questions/8056984
复制相似问题