【问题标题】:Python for loop causes system crashPython for 循环导致系统崩溃
【发布时间】:2014-05-07 07:56:16
【问题描述】:

我需要找到包含特定字符串的文本文件的所有行,并将每一行写入不同的文本文件。如何改进我的代码以防止系统在读取大文本文件(6GB 大小)的前 5,000,000,000 行时崩溃?编译代码后,我的电脑运行缓慢,突然死机。即使我停止编译过程,内存仍然被占用并且出现同样的问题。我的 IDE 是 Spyder,我使用 Python 2.7。 谢谢!

我的代码是:

import fileinput

ot = 'N'
j = 1
i = 1
string = "ABCD"

for line in fileinput.input(['/../myfile.txt']):
    if i<=5000000000:
        if string in line:
            output = open(ot + str(j) + '.txt', 'w')
            output.write(line)
            output.close()
            j += 1
        i += 1

【问题讨论】:

  • 尝试使用context managerwith line in open('file.txt', 'r'):
  • 如果你尝试读取一个 50MB 的文件,结果如何?
  • @Chien-Wei Huang,代码在 i = 1,000,000 和较小的文本文件(例如 250MB)的情况下最大工作量,但对于超过这些文件,我的系统显示内存不足(我的操作系统是 UBUNTU 13.10 和我的电脑内存为 8GB)。
  • 如果去掉output = open(ot + str(j) + '.txt', 'w')output.close()这三行,会发生什么?
  • 我用 2GB 文件测试,没有在 Mac 环境中写入文件,这行得通。不知道问题是与一个目录中的文件数限制有关,也可能与操作系统环境有关。我的程序内存只需要 1X MB。

标签: python performance for-loop bigdata


【解决方案1】:

你可以试试这个代码:

file_input = open('mhyfile.txt','r')
for line in file_input:
    #Your code here

for line in file_input: 循环将逐行读取文件。但是我在我的 linux 系统中测试并发现 fileinput.input() 不再使用内存。我认为您应该提供有关您的问题的更多信息。

一个可能的问题是您将太多文件写入磁盘并导致系统崩溃。您可以尝试将选定的行写入一个文件并标记行号j

【讨论】:

    【解决方案2】:
    from itertools import izip
    ot = 'N%d.txt'
    j = 1
    lim = 5*10**9
    with open('myfile.txt') as f:
        #the xrange part replaces the i < 5e9 thing you had.
        for line, _ in izip(f,xrange(lim)):
            if 'ABCD' in line:
                output = open(ot % j, 'w')
                output.write(line)
                output.close()
                j += 1
    

    这应该可以正常运行,但如果您的文件很大,则可能需要一段时间,尽管它不应该占用太多内存。

    编辑
    我添加了 izip 以避免占用大量内存。 izip 与 zip 类似,只是它返回的是生成器而不是列表。

    【讨论】:

    • @Emely_sh 实际上,我认为这可能会使所有内容都加载到内存中?哈哈。如果是这样,我不知道为什么它在其他人不会的情况下起作用。在 python3 中, zip 将返回一个 zip 对象,然后它会在迭代时懒惰地给出每个项目。但是在 python 2 中,我认为这只是将第一行(最多 50 亿行)强制放入一个元组列表中。如果文件足够大,这应该会占用大量内存。
    • 我的电脑使用 zip 并没有崩溃,但它比 izip 慢; izip 只使用了 14% 的内存 :) 谢谢
    【解决方案3】:

    仅选择迭代器的前 limit 项的规范方法是使用 islice from itertools - islice(my_file, limit) 类似于 my_file.readlines()[:limit],除了它避免将整个文件读入内存。仅计算其中包含给定字符串的行只是稍微复杂一点:使用生成器表达式仅获取这些行,然后 islice 那些

    from itertools import islice
    ot = 'N%d.txt'
    limit = 5000000000  
    
    with open('myfile.txt') as f:
       lines = (line for line in f if 'ABCD' in line)
       for j, line in enumerate(islice(lines, limit), start=1):
           with open(it % j, 'w') as out:
              out.write(line)
    

    【讨论】:

      【解决方案4】:

      试试这个:

      file_num = 1
      
      with open('myfile.txt', 'r') as file:
          for i in range(5000000000):
              if file.readline(i) == 'ABCD':
                  with open('N' + file_num + '.txt', 'w') as write_file:
                      write_file.write(file.readline(i))
                      file_num += 1
      

      不确定它对崩溃有多大帮助,但它更干净。请在下方提问。

      【讨论】:

      • 我收到此错误“for i in range(5000000000): MemoryError”
      • @Emely_sh 试试xrange
      • 您好,只是一个建议,不要使用“file”关键字作为文件处理程序。此外,您可以只遍历文件而不调用“file.readline(i)”。而 file.readline(i) == 'ABCD' 是错误的。该操作正在检查包含“ABCD”的行,而不是该行是“ABCD”。还读取打开文件的默认模式,因此标志 'r' 是多余的。
      • @Broseph 我在使用 xrange 时没有遇到内存问题,但 Spyder 意外关闭,问题仍然存在。
      • @Emely_sh 试试下面 locoyou 的回答。
      猜你喜欢
      • 1970-01-01
      • 2020-01-11
      • 1970-01-01
      • 1970-01-01
      • 2019-07-12
      • 2013-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多