为了账号安全,请及时绑定邮箱和手机立即绑定

Outlook 中处理数千封电子邮件时内存不足,如何释放 COM 对象的内存?

Outlook 中处理数千封电子邮件时内存不足,如何释放 COM 对象的内存?

呼啦一阵风 2023-07-18 13:38:29
我有一个 Python 脚本,可以获取收件箱文件夹中所有电子邮件的电子邮件 ID。但是,当 Outlook 达到数千封电子邮件时,会引发内存不足异常。例外:Printing emails...Traceback (most recent call last):  File "print_emails.py", line 53, in main    print_emails()  File "print_emails.py", line 43, in print_emails    primary_emails, primary_email_ids = get_emails_and_ids(primary_source_folder)  File "print_emails.py", line 29, in get_emails_and_ids    property_accessor = item.PropertyAccessor  File "C:\Program Files\Python38\lib\site-packages\win32com\client\__init__.py", line 474, in __getattr__    return self._ApplyTypes_(*args)  File "C:\Program Files\Python38\lib\site-packages\win32com\client\__init__.py", line 467, in _ApplyTypes_    self._oleobj_.InvokeTypes(dispid, 0, wFlags, retType, argTypes, *args),pywintypes.com_error: (-2147352567, 'Exception occurred.', (4096, 'Microsoft Outlook', 'Out of memory or system resources. Close some windows or programs and try again.', None, 0, -2147024882), None)Press enter to exit...我尝试了两种不同的方法:迭代一次(get_emails_and_ids)和两次(get_emails和get_email_ids)。PropertyAccessor似乎和获得了几千次有关。如果我只是使用 来获取电子邮件get_emails,它在处理 38,000 封电子邮件时运行良好,但是当我开始使用数千次来获取 ID 时PropertyAccessor,内存就会耗尽。我必须释放旧的属性访问器吗?安装:pip install -U pypiwin32代码:#!/usr/bin/env pythonfrom typing import Any, List, Tuple, Setimport tracebackimport win32com.clientPidTagInternetMessageId = "http://schemas.microsoft.com/mapi/proptag/0x1035001F"primary_account_email = "user@domain.tld"primary_source_folder_name = "Inbox"def get_emails(folder) -> List:    return [item for item in folder.Items if "_MailItem" in str(type(item))]def get_email_ids(emails) -> Set[str]:    return {email_id for email in emails if len(email_id := email.PropertyAccessor.GetProperty(PidTagInternetMessageId)) > 0}
查看完整描述

2 回答

?
慕娘9325324

TA贡献1783条经验 获得超4个赞

尝试将“ for”循环替换为从 1 到 Items.Count 的循环(使用 Items(i) 检索项目) - 不确定 Python,但在其他语言中,“ ”foreach循环倾向于保留引用的集合的所有项目,直到循环退出。



查看完整回答
反对 回复 2023-07-18
?
12345678_0001

TA贡献1802条经验 获得超5个赞

我的解决方案是不将所有电子邮件(MailItem 对象)存储在列表中。如果我需要列表中的电子邮件,当我处理电子邮件时,我应该list.pop()立即将其从列表中删除。使用PropertyAccessor并将电子邮件保留在列表中会导致 Outlook 将对象保留在内存中,并导致 Outlook 内存不足。


我摆脱了get_emails和get_emails_and_ids函数并重新编写了该get_email_ids函数以仅存储电子邮件消息 ID,但不将电子邮件对象存储在列表中:


def get_email_ids(folder) -> Tuple[Set[str], int]:

    email_ids = set()


    items = folder.Items

    i = 0

    for item in items:

        if "_MailItem" in str(type(item)):

            i += 1


            property_accessor = item.PropertyAccessor

            email_id = property_accessor.GetProperty(PidTagInternetMessageId)

            if len(email_id) > 0:

                email_ids.add(email_id)


            if i % 500 == 0:

                print(f"    Retrieved {i} email IDs.")


    return email_ids, i

我编写的另一个脚本现在快了很多,至少需要 10 分钟。以前,它每秒处理几封电子邮件,需要几个小时。


查看完整回答
反对 回复 2023-07-18
  • 2 回答
  • 0 关注
  • 97 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信