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

Python 高磁盘使用率是否意味着更快的文件读/写操作?,python,file-handling,Python,File Handling,我正在编写一个python脚本,在这个脚本中,我逐行读取一个大文件~5 GB,对每行进行一些修改,然后将其写入另一个文件 当我使用函数file.readlines()读取输入文件时,我的磁盘使用率达到90%,磁盘速度达到+100Mbps(我知道这个方法不应该用于大文件) 我还没有测量上述情况下的程序执行时间,因为我的系统没有响应(内存已满) 当我使用下面这样的迭代器时(这就是我在代码中实际使用的迭代器) 我的磁盘使用率保持在

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

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

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

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

我的磁盘使用率保持在<10%,速度<5 Mbps,程序需要约20分钟才能完成5 GB文件的执行。如果我的磁盘使用率很高,这一次不是更低吗

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


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

这完全取决于您读取文件时使用的缓冲区大小

让我们看一个例子:

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

缓冲区大小为2个字符

然后,您必须使用至少10个系统调用来读取整个时间

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

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


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

您不仅需要文件的RAM,还需要输入和输出缓冲区以及修改文件的第二个副本。这很容易压倒你的公羊。 如果不想读取、修改或写入for循环中的每一行,则可能需要将一些行组合在一起。这可能会加快读/写速度,但会增加一些算法开销。在一天结束时,我会使用逐行的方法。 嗯!
LuI

我认为您的主要问题不是读取文件,因为您使用的是open(),而是检查您在这里执行的操作:

对每行进行一些修改,然后将其写入 另一个文件

因此,请尝试在不修改/写入其他文件的情况下读取该文件,以了解系统读取该文件所需的时间

以下是我在阅读、和之后如何在我的环境中进行测试

首先,创建了一个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()更改缓冲选项:

不应使用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是否是限制部分,您可以尝试使用system copy utility简单地复制文件。如果大约需要20分钟,则该过程是磁盘IO绑定的,如果速度快得多,则不能忽略对行的修改


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

我怀疑一些磁盘使用是虚拟ram,因为它不能在内存中保存整个文件。这会显著增加磁盘使用率,但会降低操作速度。我的系统内存大小为8 GB,因此我认为它实际上可以将整个文件加载到内存中。但不确定。您的磁盘使用将分为两部分:您正在读取原始文件,但当RAM达到极限时,部分RAM将交换到磁盘以“扩展”它。这是一种特别严重的磁盘使用情况,您应该尽量避免这种情况——例如,在读取数据时对其进行处理,并立即释放内存。您可能有很多RAM,但内存中的存储通常不太理想。此外,操作系统保留了大部分RAM,编译器也是如此。目前,我有8GB的RAM,只有0.5GB的空闲内存(我没有运行任何大型程序!)。在打开10个Chrome选项卡的情况下,尝试查看机器中的可用RAM(在linux中使用
free
),我有4.7GB的可用RAM。第一个函数实际上会将整个文件加载到内存中。第二个函数使用缓冲区。我尝试过给它提供不同的缓冲区大小,但这似乎并没有提高性能。第一个函数也必须使用缓冲区。但是它确实是一个很大的缓冲区。任何比行本身长的缓冲区大小都不会对性能产生影响,因为换行符之后,缓冲区的其余部分将不会被填充。因此,您仍然使用相同数量的系统调用。这解释了为什么较高的缓冲区值不会影响性能。我的印象是,更高的缓冲区会使程序在内存中加载更多的文件行。性能上唯一的孤岛是使用大缓冲区加载所有内容并编辑内存中的行。感谢链接。我并没有在代码中实际使用.readlines()。我在问题中使用它来与我的代码进行比较。我不明白的是,为什么程序没有充分利用我的系统
# --------------------------------------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
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