高磁盘使用率是否意味着更快的文件 read/write 操作?

Does high disk usage mean faster file read/write operations?

我正在编写一个 python 脚本,我在其中逐行读取一个大约 5 GB 的大文件,对每一行进行一些修改,然后将其写入另一个文件。

当我使用函数file.readlines()读取输入文件时,我的磁盘使用率达到~90%并且磁盘速度达到+100Mbps(我知道这种方法不应该用于大文件).

我没有测量上述情况下的程序执行时间,因为我的系统变得无响应(内存已满)。

当我像下面这样使用迭代器时(这就是我在代码中实际使用的)

with open('file.csv', 'r') as inFile:
    for line in inFile:

我的磁盘使用率仍然低于 10%,速度低于 5 Mbps,程序完成一个 5 GB 文件的执行大约需要 20 分钟。如果我的磁盘使用率很高,这个时间会不会更低?

此外,读取 5 GB 是否真的需要大约 20 分钟,逐行处理,对每一行进行一些修改,最后将其写入一个新文件,还是我做错了什么?

我不明白的是为什么程序在执行 io 操作时没有充分利用我的系统的潜力。因为如果是这样,那么我的磁盘使用率应该更高,对吧?

这仅取决于您用于读取文件的缓冲区大小。

让我们看一个例子:

您有一个包含 20 个字符的文件。

您的缓冲区大小为 2 个字符。

那么整个阅读时间至少要使用10次系统调用

系统调用是一个非常昂贵的操作,因为内核必须切换执行上下文。

如果你有一个 20 个字符大小的缓冲区,你只需要 1 个系统调用,因此只需要一个内核陷阱。

我假设第一个函数只是在内部使用了更大的缓冲区。

您不仅需要文件的 RAM,还需要输入和输出缓冲区以及修改文件的第二个副本。这很容易使您的 RAM 不堪重负。 如果您不想在 for 循环中读取、修改和写入每一行,您可能希望将一些行组合在一起。这可能会使 reading/writing 更快,但代价是更多的算法开销。在一天结束时,我会使用逐行方法。 喂! 吕

我不认为你的主要问题是读取文件,因为你正在使用 open(),相反我会检查你在这里做什么:

make some modifications in each of the lines, and then write it to another file.

因此,请尝试在不对另一个文件进行修改/写入修改的情况下读取该文件,以了解您的系统仅读取该文件需要多少时间。

以下是我在阅读 this,, and this

后在我的环境中进行的测试

首先,创建了一个 1.2GB 的文件:

timeout 5 yes "Ergnomic systems for c@ts that works too much" >> foo

我没有使用 dd 或 truncate,这会导致读取文件时出现内存错误。

现在一些 I/O 测试读取文件,这是一个已经优化的操作,就像@Serge Ballesta 提到的:

#!/usr/bin/python
with open('foo') as infile:
    for line in infile:
        pass
    print 'file readed'

$ time python io_test.py
file readed

real    0m2.647s
user    0m2.343s
sys     0m0.327s

使用 open() 更改缓冲选项:

# --------------------------------------NO BUFFERING
with open('foo','r',0) as infile:
    for line in infile:
        pass
    print 'file readed'

$ time python io_test.py
file readed

real    0m2.787s
user    0m2.406s
sys     0m0.374s

# --------------------------------------ONE LINE BUFFERED
with open('foo','r',1) as infile:
  for line in infile:
    pass
  print 'file readed' 

$ time python io_test.py
file readed

real    0m4.331s
user    0m2.468s
sys     0m1.811s
# -------------------------------------- 70 MB/s
with open('foo','r',700000000) as infile:
  for line in infile:
    pass
  print 'file readed' 

$ time python io_test.py
file readed

real    0m3.137s
user    0m2.311s
sys     0m0.827s

为什么不应该使用 readlines:

with open('foo') as f:
    lines = f.readlines()
    for line in lines:
        pass

$ time python io_test.py

real    0m6.428s
user    0m3.858s
sys     0m2.499s

在Python中逐行读取文件已经是一个优化的操作:Python从磁盘加载一个内部缓冲区并将其逐行提供给调用者。这意味着行标识已经由 Python 解释器在内存中完成。

通常,当磁盘访问是限制因素、内存限制或处理器限制时,处理可以是磁盘 IO 限制。如果您使用某些网络,它可以是网络 IO 绑定或远程服务器绑定,仍然取决于限制因素是什么。当您逐行处理文件时,进程不太可能受内存限制。要确定磁盘 IO 是否是限制部分,您可以尝试使用系统复制实用程序简单地复制文件。如果大约需要20分钟,那么这个过程是磁盘IO绑定的,如果快得多,那么线路上的修改就不能忽略了。

无论如何,在内存中加载一个大文件总是一个坏主意...