我有一些巨大的(几千兆字节)ASCII文本文件,我需要逐行读取,将某些列转换为浮点数,并对这些数字执行一些简单的操作。这是非常简单的东西,除了我认为必须有一种方法来加快它的速度。该程序从不使用相当于100%的CPU内核,因为它花了很多时间等待I / O.与此同时,它花费了足够的时间进行计算而不是I / O,只需要8-10 MB /秒的原始磁盘I / O.我见过我的硬盘好多了。
它可能有助于在单独的线程中进行I / O和处理吗?如果是这样,实现这个的有效方法是什么?一个重要的问题是如何处理内存分配以保持每一行,这样我就不会遇到瓶颈。
编辑:我现在正在使用D编程语言,版本2标准库,主要是更高级别的功能。 std.stdio.File使用的缓冲区大小为16 KB。
答案 0 :(得分:1)
如果你没有达到100%的CPU,那么你就受到了I / O限制,并且多线程不会看到太多/任何改进 - 你只需要几个线程等待I / O.实际上,如果他们访问文件的不同部分,你可能会引入磁盘寻找并使事情变得更糟。
首先看一下简单的事情:你能增加I / O可用的缓冲RAM量吗? (例如在C ++中,FILE对象的标准I / O缓冲区很小(例如4kB),设置较大的缓冲区(例如64kB)会对吞吐量产生巨大影响)。
您可以在I / O请求中使用更大的缓冲区大小:例如将64KB原始数据读入一个大缓冲区,然后自己处理,而不是一次读取一行或一个字节。
您在输出任何数据吗?通过在RAM中缓存它而不是立即将其写回磁盘,您可以将IO限制为纯粹读取输入文件,并帮助提高速度。
你可能会发现,一旦你加载了大量的数据缓冲区,你开始变成了CPU绑定,那么你可以考虑多线程 - 一个线程来读取数据,另一个线程来处理它。
答案 1 :(得分:0)
如果你有足够的内存,你可以把整个文件读成一个字符串,在行分隔符上标记它,然后处理你想要的标记。
在java中,您将使用StringBuilder对象将文件内容读入其中。您还希望使用以下内容启动具有足够内存限制(在此示例中为2GB)的jvm:
java -Xmx 2048 -Xms 2048 -jar MyMemoryHungryApp.jar
如果您不想将整个文件读入字符串,您可以批量迭代地读取它并处理批次。
实际上,根据文件格式的细节,你可以使用CSVReader一个开源Java包(project page)来读取你的文件到readAll()方法的内存,你就会结束用List<String[]>
来你可以去镇上。)。
答案 2 :(得分:0)
首先,我会接受你所拥有的程序,并获得它的叠印。这将确定I / O花费了多少时间,以及CPU的耗费量。
然后,如果I / O占主导地位,我会确保我正在读取尽可能大的缓冲区,以尽量减少磁头运动。
然后,如果我看到I / O在CPU上等待,然后CPU等待I / O,我会尝试进行异步I / O,这样一个缓冲区就可以加载而CPU在另一个上运行。 (或者你可以用读者线程来读取备用缓冲区。)
如果I / O不占优势并且CPU占主导地位,那么我会看到什么叠加告诉我有关CPU活动的信息。如果在浮点数的去格式化中花费了过多的时间,并且如果数字格式相当简单,我会考虑自己解析它们,因为我可以利用更简单的格式。
这有帮助吗?
答案 3 :(得分:0)
通常情况下,操作系统会尝试提前读取,如果您不受CPU限制,则应该接近硬盘限制速度。
原因可能是:
当你受CPU限制时,你应该开始考虑更有效的数据解析。