【问题标题】:Python script uses all RAMPython 脚本使用所有 RAM
【发布时间】:2018-10-06 20:05:23
【问题描述】:

我有一个 Python 脚本,用于解析大型文档中的电子邮件。该脚本正在使用我机器上的所有 RAM,并使其锁定到我必须重新启动它的位置。我想知道是否有一种方法可以限制这一点,或者甚至在完成读取一个文件并提供一些输出后暂停。任何帮助都会非常感谢。

#!/usr/bin/env python

# Extracts email addresses from one or more plain text files.
#
# Notes:
# - Does not save to file (pipe the output to a file if you want it saved).
# - Does not check for duplicates (which can easily be done in the terminal).
# - Does not save to file (pipe the output to a file if you want it saved).
# Twitter @Critical24 - DefensiveThinking.io 


from optparse import OptionParser
import os.path
import re

regex = re.compile(("([a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`"
                    "{|}~-]+)*(@|\sat\s)(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(\.|"
                    "\sdot\s))+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)"))

def file_to_str(filename):
    """Returns the contents of filename as a string."""
    with open(filename, encoding='utf-8') as f: #Added encoding='utf-8'
    return f.read().lower() # Case is lowered to prevent regex mismatches.

def get_emails(s):
    """Returns an iterator of matched emails found in string s."""
    # Removing lines that start with '//' because the regular expression
    # mistakenly matches patterns like 'http://foo@bar.com' as '//foo@bar.com'.
    return (email[0] for email in re.findall(regex, s) if not email[0].startswith('//'))

import os
not_parseble_files = ['.txt', '.csv']
for root, dirs, files in os.walk('.'):#This recursively searches all sub directories for files
for file in files:
    _,file_ext = os.path.splitext(file)#Here we get the extension of the file
    file_path = os.path.join(root,file)
    if file_ext in not_parseble_files:#We make sure the extension is not in the banned list 'not_parseble_files'
       print("File %s is not parseble"%file_path)
       continue #This one continues the loop to the next file
    if os.path.isfile(file_path):
        for email in get_emails(file_to_str(file_path)):
            print(email)

【问题讨论】:

  • 这些文件有多大?除非您的模式可以跨越多行,否则您可以尝试逐行读取文件并将其应用于每一行,即使用文件f 作为生成器,而不是使用readreadlines
  • 另外,我刚刚注意到您的评论说脚本是从“纯文本文件”中提取的,但 .txt 在您的 non 可解析文件列表中。那应该是 可解析 文件的列表吗?
  • 我发现你的问题"([a-z0-9!#$%&'*+\/=?^_{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_" "{|}~-]+)*(@|\sat\s)(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(\.|" "\sdot\s))+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)"
  • 问题中代码的一些缩进被破坏了。
  • 在最坏的情况下,如果您有一个 8 gig 的文件并将其读入内存,那么您将使用 8 gig 的内存(加上一些开销)。如果您随后尝试解析并返回解析后的数据,则很容易导致 另一个 8 gigs 的内存被使用。

标签: python python-3.x ram


【解决方案1】:

您似乎正在使用 f.read() 将最大 8 GB 的文件读入内存。相反,您可以尝试将正则表达式应用于文件的每一行,而无需将整个文件放在内存中。

with open(filename, encoding='utf-8') as f: #Added encoding='utf-8'
    return (email[0] for line in f
                     for email in re.findall(regex, line.lower())
                     if not email[0].startswith('//'))

不过,这仍然需要很长时间。另外,我没有检查您的正则表达式是否存在问题。

【讨论】:

    猜你喜欢
    • 2014-06-30
    • 2019-07-23
    • 1970-01-01
    • 2022-08-13
    • 2021-03-30
    • 2022-01-24
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多