【问题标题】:python, reducing memory consumption and making this code more efficient?python,减少内存消耗并使这段代码更高效?
【发布时间】:2016-05-22 09:56:19
【问题描述】:

我已经编写了这段代码(它可以工作 - 我在小批量的 MBOX 文件上尝试过)。但是,当我在一个大小为 2.9 GB、大约 50,000 封邮件的 MBOX 文件上尝试它时,内存消耗猛增,导致计算机无法使用。这段代码在内存消耗方面有什么问题,有没有办法解决它,例如使代码处理增量而不是整体? 此脚本的目标是生成一个 CSV 文件,其中 x 作为日期,Y 作为每个日期收到的消息计数,以便绘制它们并生成电子邮件的统计表示。 未来:我打算扩展它,阅读电子邮件并按时间顺序生成 pdf 输出,因此需要对其进行排序(内存消耗猛增)

    import mailbox
    from email.utils import parsedate
    from dateutil.parser import parse
    import itertools
    import plotly.plotly as py
    from plotly.graph_objs import *
    import plotly.tools as tls
    import csv
    from itertools import izip

    path = 'mail.mbox'
    mbox = mailbox.mbox(path)

    def extract_date(email):
        date = email.get('Date')
        return parsedate(date)

 #sort the email by a given date
    sorted_mails = sorted(mbox, key=extract_date)
    mbox.update(enumerate(sorted_mails))
    mbox.flush()

 #it finds all the dates within the MBOX and split
    all_dates = []
    mbox = mailbox.mbox(path)
    for message in mbox:
        all_dates.append( str( parse( message['date'] ) ).split(' ')[0] )

 #counts the number of emails per given date
    email_count = [(g[0], len(list(g[1]))) for g in itertools.groupby(all_dates)]
    email_count[0]

 #makes a list of (x,y)
    x = []
    y = []
    for date, count in email_count:
        x.append(date)
        y.append(count)

 #produce a CSV file of X and Y, for plotting
    with open('data.csv', 'wb') as f:
        writer = csv.writer(f)
        writer.writerows(izip(x, y))
   """
   data = Data([x, y])
   plot_url = py.iplot(Data, filename='line-scatter' )
  """
    py.iplot( Data([ Scatter( x=x, y=y ) ]) )

【问题讨论】:

  • 我建议在逐行执行代码时调试代码并检查内存使用情况。如果您能告诉我们您想要实现的目标,帮助您会更容易。
  • 如果使用外部工具是可以接受的,那么仅使用formail -czxDate: -s <mbox 之类的内容提取日期将显着减少后续处理步骤中不必要的 I/O 数量。一个缺点是,这使得更难精确定位,例如在管道的任何后期阶段具有错误标头的消息。
  • @jochen ,内存消耗发生在 sorted_mails 块周围。我正在尝试生成带有日期和每个日期的消息/电子邮件接收者数量的 CSV 输出。为方便起见对 CSV 进行排序,稍后我计划扩展代码以读取消息并按时间顺序在 pdf 上生成输出。
  • @tripleee,我之前想过,但这无济于事 - 因为我正在尝试对电子邮件进行统计表示,并且通过 +50K 的外部工具提取日期将使任务繁琐。

标签: python memory mbox


【解决方案1】:

我对这些库不是很熟悉,但我认为主要问题是您正在使用这一行将所有消息读入内存:

sorted_mails = sorted(mbox, key=extract_date)

这个脚本的目标是什么?你真的需要对任何东西进行排序吗?如果您只需要生成一个包含每个日期计数的 CSV,请尝试以下操作:

import mailbox
from email.utils import parsedate
from dateutil.parser import parse
import itertools
import plotly.plotly as py
from plotly.graph_objs import *
import plotly.tools as tls
import csv
from itertools import izip

path = 'mail.mbox'
mbox = mailbox.mbox(path)

# map date to number of emails seen on that date
date_counts = {}

for message in mbox:
    date = str( parse( message['date'] ) ).split(' ')[0]
    try:
        date_counts[date] += 1
    except KeyError:
        date_counts[date] = 1

with open('data.csv', 'wb') as f:
    writer = csv.writer(f)
    for date in date_counts:
        writer.writerow([date, date_counts[date]])

【讨论】:

  • 我们的目标是生成一个 csv,以便稍后统计地绘制数据,以直观地表示电子邮件。但也有计划扩展代码,阅读消息并按照首先收到的顺序在 pdf 上生成输出。所以我在技术上需要对它进行排序以备后用。但是当我省略排序时,您的代码实际上可以工作。
  • 您应该在不同的脚本中进行任何排序,因为对 2.9 GB 的文件进行排序会很昂贵,而且没有必要进行计数。
  • 我明白你的意思!将排序任务与脚本分开是有意义的。在此过程中,您认为在排序后生成 al 50k l 电子邮件的 pdf 文件有多可行?
  • 我会质疑包含 50K 电子邮件的 PDF 的有用性,但我想这是可能的。对于排序步骤,您可能需要查看 external sorting 算法,因为它们避免将所有内容同时加载到内存中。
  • 太棒了!感谢您的帮助和直率。干杯!
猜你喜欢
  • 1970-01-01
  • 2015-05-10
  • 2013-06-13
  • 1970-01-01
  • 1970-01-01
  • 2021-11-21
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多