任何更快的选择?

kau*_*hik 0 python performance

我必须从特定的行号读取文件,我知道行号说"n":我一直在考虑两种选择:

  1. for i in range(n):
        fname.readline()
    k=readline()
    print k
    
    Run Code Online (Sandbox Code Playgroud)
  2. i=0
    for line in fname:
        dictionary[i]=line
        i=i+1
    
    Run Code Online (Sandbox Code Playgroud)

但我想知道更快的替代方案,因为我可能必须在20000次不同的文件上执行此操作.还有其他更好的选择吗?

我甚至想知道是否有其他性能增强方法用于简单循环,因为我的代码有嵌套循环

感谢你

Ale*_*lli 5

如果文件不是太大,标准库的linecache模块非常好 - 它可以让你非常直接地询问这样一个文件的第N行.

如果文件巨大的,我建议类似的信息(警告,未经测试的代码):

def readlinenum(filepath, n, BUFSIZ=65536):
  bufs = [None] * 2
  previous_lines = lines_so_far = 0
  with open(filepath, 'b') as f
    while True:
      bufs[0] = f.read(BUFSIZ)
      if not bufs[0]:
        raise ValueError('File %s has only %d lines, not %d',
                         filepath, lines_so_far, n)
      lines_this_block = bufs[0].count('\n')
      updated_lines_count = lines_so_far + lines_this_block
      if n < updated_lines_count:
          break
      previous_lines = lines_so_far
      lines_so_far = updated_lines_count
      bufs[1] = bufs[0]
    if n == lines_so_far:
      # line split between blocks
      buf = bufs[1] + bufs[0]
      delta = n - previous_lines
    else:  # normal case
      buf = bufs[0]
      delta = n = lines_so_far
    f = cStringIO.StringIO(buf)
    for i, line in enumerate(f):
      if i == delta: break
    return line.rstrip()
Run Code Online (Sandbox Code Playgroud)

一般的想法是在大块中读取文件为二进制文件(至少与最长的行一样大) - 从二进制文件到"文本"的处理(在Windows上)对于大文件来说是昂贵的 - 并使用.count大多数块上的快速字符串方法.最后,我们可以在单个块上进行行解析(在寻找的行跨越块边界的异常情况下最多两个).

这种代码需要仔细测试和检查(我在这种情况下没有执行),容易出现一个一个和其他边界错误,所以我建议它只用于真正庞大的文件 - 那些会如果使用linecache(它只是将整个文件吸收到内存而不是通过块工作)本质上是内存.例如,在具有4GB字节RAM的典型现代机器上,我开始考虑用于超过GB或2的文本文件的这种技术.

编辑:评论者不相信读取文件的二进制文件比文本模式所需的处理速度快得多(仅限Windows).为了说明这是多么错误,让我们使用'U'("通用换行符")选项来强制在Unix机器上进行行结束处理(因为我没有Windows机器来运行它;-).使用通常的kjv.txt文件:

$ wc kjv.txt
  114150  821108 4834378 kjv.txt
Run Code Online (Sandbox Code Playgroud)

(4.8 MB,114 Klines) - 大约我之前提到的文件大小的1/1000:

$ python -mtimeit 'f=open("kjv.txt", "rb")' 'f.seek(0); f.read()'
100 loops, best of 3: 13.9 msec per loop
$ python -mtimeit 'f=open("kjv.txt", "rU")' 'f.seek(0); f.read()'
10 loops, best of 3: 39.2 msec per loop
Run Code Online (Sandbox Code Playgroud)

也就是说,对于线端处理来说,这只是成本的三分之一(这是在旧式笔记本电脑上,但这个比例在其他地方也应该是可重复的).

当然,在线上循环阅读甚至更慢:

$ python -mtimeit 'f=open("kjv.txt", "rU")' 'f.seek(0)' 'for x in f: pass'
10 loops, best of 3: 54.6 msec per loop
Run Code Online (Sandbox Code Playgroud)

并使用readline如所提到的评论(缓冲效率低于直接在文件上循环)最差:

$ python -mtimeit 'f=open("kjv.txt", "rU")' 'f.seek(0); x=1' 'while x: x=f.readline()'
10 loops, best of 3: 81.1 msec per loop
Run Code Online (Sandbox Code Playgroud)

如果,正如问题所提到的那样,有20,000个文件要读(比如它们都是小的,按此顺序排列kjv.txt),最快的方法(在单个gulp中以二进制模式读取每个文件)应该花费大约260秒,4-5分钟,而最慢的(基于readline)应该花费大约1600秒,差不多半小时 - 对于许多人来说,这是一个非常显着的差异,我会说大多数实际的应用程序.