【问题标题】:JavaMail, IMAP, performance with large number of foldersJavaMail、IMAP、大量文件夹的性能
【发布时间】:2017-12-07 19:36:14
【问题描述】:

我们正在为 IMAP 帐户开发基于 java 的邮件客户端,并使用最新的 java mail api (1.5.6)。我们的客户拥有包含 400 多个文件夹的邮件帐户。用户对文件夹执行检查邮件并在每个文件夹上迭代并获取新消息,例如,

folder.getMessagesByUid(lastStoredUID, UIDFolder.LastUID)

或获取未读邮件的计数需要太多时间,因为文件夹数量巨大。 (我们必须迭代 400 个文件夹)

为了提高性能,我们在线程中使用了并行工作连接,并且我们只有一个 SESSION 实例,但每个线程(连接)都有自己的 STORE 实例。当我们必须获取新消息时,我们会动态生成 10 个线程及其 STORE 实例,分别连接/登录它们,获取该 STORE 上的文件夹实例,打开文件夹,执行文件夹操作,然后关闭文件夹并关闭 SESSION。但对我来说,我不清楚我是否必须保留文件夹实例,我也不清楚文件夹是否应该保持打开状态,或者我们是否应该明确关闭,否则我们可能会全部打开(将关闭操作留给邮件服务器)。

在我目前的实现中,

new Thread() {
    public void run() {
        //Get a new store instance
        Store tempStore = MySingleSession.getStore("imap");
        tempStore.connect(..);

        //Get a folder for example inbox
        Folder inbox = tempStore.get("INBOX");

        inbox.open(Folder.READ);

        // Perform get new messages
        inbox.getMessagesByUd(lastUID, UIDFolder.MaxUID);

        inbox.close();

        tempStore.close();
        ..

检查性能时,我发现打开/关闭文件夹需要很长时间,尤其是在包含超过 100.000 条消息的文件夹上。而且我看到,即使我关闭了文件夹的存储,文件夹仍保持打开状态,如果我们不明确关闭该文件夹,我们可以对其进行操作。如果我更改实现并且不明确关闭文件夹并保持打开状态,这种机制有什么缺点?

  • 将文件夹引用保存在以全名作为关键字的哈希表中,例如 “收件箱”-> IMAPFolder 并在任何操作(getMessages)之前执行 isOpened 检查,但完成后,不要像我当前的实现那样显式关闭。这样做时,我们可能打开了 400 个文件夹,邮件服务器和邮件服务器关闭它们可能看起来很糟糕,但我会先检查每个文件夹的操作,是否打开。因此,文件夹将尽可能保持打开状态(直到邮件服务器关闭连接),如果再次需要相同的文件夹,我们不必再次打开它。

  • 我不明白,为什么我仍然可以对商店关闭的文件夹进行操作?

  • ma​​il.imap.connectionpoolsize 的默认值为 1,在这种情况下增加该值是否有帮助?

  • 我不明白下面这种情况会发生什么?

    Store tempStore = MySingleSession.getStore("imap");
    
    tempStore.connect(..);
    
    Folder f = tempStore.getFolder("INBOX");
    
    f.open(Folder.READ_ONLY);
    
    // close the store!!!
    tempStore.close();
    
    // now folder f becomes closed,
    // but we may open it again even if its Store is disconnected!
    
    f.open(Folder.READ_ONLY);
    
    // we can continue operating on folder f
    
  • 哪种方法更好,将文件夹引用保存在全名键控的 hastable 中,还是每次都执行 tempStore.getFolder(foldername)?比如我们要处理INBOX,第一个选项使用

IMAPFolder f = folderCache.get("INBOX"); // 假设已经放入 hashtable folderCache

IMAPFolder f = tempStore.getFolder("INBOX");

我按需生成 Store 实例并在之后关闭它们,以免使用邮件服务器上的大量资源。但是再次打开文件夹而不是手动关闭不是一个好方法,因为它仍然使用资源?或者使用这种方式是可以接受的,因为邮件服务器可能会在需要时关闭它,我们只需要检查是否

  • 如果文件夹已经打开,继续操作,
  • 如果文件夹是关闭的,先打开再操作,保持打开状态以备不时之需?

【问题讨论】:

  • 由于您必须随时处理故障,您应该在尝试操作之前检查文件夹是否打开,以避免在正常路径上浪费时间。只需尝试操作并在抛出异常时尝试恢复。

标签: java multithreading email jakarta-mail imap


【解决方案1】:

一篇文章的问题太多了。让我试着回答其中的几个......

关闭文件夹后,您不应使用该文件夹中的任何消息对象,因此只有在使用完其消息后才关闭该文件夹。

如果单个用户有 400 个文件夹,您可以使用单个 Store 连接,因为每个打开的文件夹都会有自己的连接。

如果您经常打开和关闭文件夹,增加连接池大小会有所帮助,因为已关闭文件夹的连接将被添加到池中并在您打开新文件夹时重复使用,而无需创建新连接。

关闭存储应关闭该存储的所有文件夹,但如果涉及多个线程,则存在固有的竞争条件。关闭 Store 是一种在使用完毕后清理所有连接的方法,而不是防止其他线程重新打开文件夹的方法。

为关闭的文件夹缓存文件夹对象不太可能比每次调用 getFolder 有很大优势。

【讨论】:

  • 感谢您的回复。但我有点困惑。在另一篇帖子stackoverflow.com/questions/44826628/… 你说:* 你可以尝试使用多个商店到同一个服务器并多次连接以获得多个连接,然后将请求并行拆分到连接中。 * 使用这种方法,它变得非常快,但现在您说您可以使用单个存储,因为每个文件夹都有自己的连接。我再次尝试使用单个商店,但增加了池大小。多存储方法总是更快
  • 某些操作在文件夹打开时使用文件夹的连接,而在文件夹关闭时使用单个单独的存储连接。后者将受益于多个商店,每个商店都有自己的连接。前者不会。
猜你喜欢
  • 2014-04-22
  • 2017-08-30
  • 1970-01-01
  • 2011-08-18
  • 2013-01-12
  • 1970-01-01
  • 2012-09-22
  • 2014-04-01
  • 2011-02-02
相关资源
最近更新 更多