如果RAM不是问题,那么是逐行读取还是将所有内容读入RAM并访问它? - Python

alv*_*vas 14 python unicode performance ram file-io

如果RAM不是问题(我在服务器上接近200GB),更快地逐行读取或将所有内容读入RAM并访问它?每行将是一个大约200-500个unicode字符的字符串.每个文件有近200万行.

逐行

import codecs
for i in codecs.open('unicodefile','r','utf8'):
  print i
Run Code Online (Sandbox Code Playgroud)

读入RAM

import codecs
for i in codecs.open('unicodefile','r','utf8').readlines():
  print i
Run Code Online (Sandbox Code Playgroud)

Gar*_*ber 15

我在一个~1MB的字典单词文件中使用了cProfile.我读了3次同一个文件.第一个读取整个文件,只是在存储在缓存中的情况下甚至是在游戏领域.这是简单的代码:

def first_read():
    codecs.open(file, 'r', 'utf8').readlines()

def line_by_line():
    for i in codecs.open(file, 'r', 'utf8'):
        pass

def at_once():
    for i in codecs.open(file, 'r', 'utf8').readlines():
        pass

first_read()
cProfile.run('line_by_line()')
cProfile.run('at_once()')
Run Code Online (Sandbox Code Playgroud)

以下是结果:

逐行:

         366959 function calls in 1.762 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.762    1.762 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 codecs.py:322(__init__)
        1    0.000    0.000    0.000    0.000 codecs.py:395(__init__)
    14093    0.087    0.000    0.131    0.000 codecs.py:424(read)
    57448    0.285    0.000    0.566    0.000 codecs.py:503(readline)
    57448    0.444    0.000    1.010    0.000 codecs.py:612(next)
        1    0.000    0.000    0.000    0.000 codecs.py:651(__init__)
    57448    0.381    0.000    1.390    0.000 codecs.py:681(next)
        1    0.000    0.000    0.000    0.000 codecs.py:686(__iter__)
        1    0.000    0.000    0.000    0.000 codecs.py:841(open)
        1    0.372    0.372    1.762    1.762 test.py:9(line_by_line)
    13316    0.011    0.000    0.023    0.000 utf_8.py:15(decode)
        1    0.000    0.000    0.000    0.000 {_codecs.lookup}
    27385    0.027    0.000    0.027    0.000 {_codecs.utf_8_decode}
    98895    0.011    0.000    0.011    0.000 {len}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
    13316    0.099    0.000    0.122    0.000 {method 'endswith' of 'unicode' objects}
       27    0.000    0.000    0.000    0.000 {method 'join' of 'str' objects}
    14069    0.027    0.000    0.027    0.000 {method 'read' of 'file' objects}
    13504    0.020    0.000    0.020    0.000 {method 'splitlines' of 'unicode' objects}
        1    0.000    0.000    0.000    0.000 {open}
Run Code Online (Sandbox Code Playgroud)

一次全部:

         15 function calls in 0.023 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.023    0.023 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 codecs.py:322(__init__)
        1    0.000    0.000    0.000    0.000 codecs.py:395(__init__)
        1    0.000    0.000    0.003    0.003 codecs.py:424(read)
        1    0.000    0.000    0.014    0.014 codecs.py:576(readlines)
        1    0.000    0.000    0.000    0.000 codecs.py:651(__init__)
        1    0.000    0.000    0.014    0.014 codecs.py:677(readlines)
        1    0.000    0.000    0.000    0.000 codecs.py:841(open)
        1    0.009    0.009    0.023    0.023 test.py:13(at_once)
        1    0.000    0.000    0.000    0.000 {_codecs.lookup}
        1    0.003    0.003    0.003    0.003 {_codecs.utf_8_decode}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.001    0.001    0.001    0.001 {method 'read' of 'file' objects}
        1    0.010    0.010    0.010    0.010 {method 'splitlines' of 'unicode' objects}
        1    0.000    0.000    0.000    0.000 {open}
Run Code Online (Sandbox Code Playgroud)

从结果中可以看出,一次读取整个文件的速度要快得多,但是你冒着在文件中抛出MemoryError太大的风险.


ose*_*kar 8

没有什么能阻止你在你的机器上进行测试.我创建了一个文件,每行包含1M行,结果定时为

time python something.py > /dev/null
Run Code Online (Sandbox Code Playgroud)

分别为:

逐行:

real    0m4.878s
user    0m4.860s
sys     0m0.008s
Run Code Online (Sandbox Code Playgroud)

读入RAM:

real    0m0.981s
user    0m0.828s
sys     0m0.148s
Run Code Online (Sandbox Code Playgroud)

我尝试使用2M行时会遇到MemoryError,每行300个字符,但上面的内容表明读入RAM会更快.


Win*_*ong 6

看看OP发布的示例代码,我认为对Python的作用存在误解.

即:

"逐行阅读"

import codecs
for i in codecs.open('unicodefile','r','utf8'):
  print i
Run Code Online (Sandbox Code Playgroud)

以上看起来像是逐行阅读.但是,Python将此解释为"将尽可能多的文件读入内存,然后将每个文件作为一行处理".所以实际上,上面的for循环将所有东西都读入内存.

"读入RAM"

import codecs
for i in codecs.open('unicodefile','r','utf8').readlines():
  print i
Run Code Online (Sandbox Code Playgroud)

我相信以上几乎与上面的"逐行"示例相同.即,Python正在将它全部读入内存.

如果您想测试逐行性能,则需要"readline()"而不是"readlines()"或未指定的for循环,这可能意味着"readlines()".这在StackOverflow站点的其他地方有所说明.

另一个需要考虑的方面是文件系统缓冲.如果您针对同一文件运行相同的代码,则存在文件系统缓冲污染结果的风险.正如你所说,你有200GB的RAM,这足以缓冲足够的文件来影响运行结果.

您需要执行以下操作以确保清洁测试结果:

1)将大文件从已知源复制到新文件名.(Filesystem不必是COW文件系统.)2)刷新文件系统缓存3)对文件运行第一次测试.4)删除文件5)将文件从源重新复制到另一个新文件名.6)刷新文件系统缓存7)对新文件运行第二次测试.

这将为您提供更准确的文件加载时间测试.

如果要同时将整个文件加载到内存中,filehandle.read(要读取的字节)是否可能提供更快的块读取文件内容?

在任何一种情况下,供参考:

http://docs.python.org/2/tutorial/inputoutput.html