带有 FileStreams 的 MimeKit 迭代器

Posted

技术标签:

【中文标题】带有 FileStreams 的 MimeKit 迭代器【英文标题】:MimeKit Iterator with FileStreams 【发布时间】:2020-09-01 05:51:17 【问题描述】:

我刚刚设法重写了一些现在应该能够处理用于打印的大型 MIME 文件的代码。

为此,我们以下列方式使用 MimeKit:

        var message = MimeMessage.Load(_fileStream, true);
        var iter = new MimeIterator(message);
        while (iter.MoveNext())
        
        ...
        

这里有趣的是,在我使用fileStream之前,我们曾经复制了一个HttpListenerRequest对象的inputStream,这是一个无法加载到MimeKit的NetworkStream(non-seekable)。

自从添加了 fileStream,对于一个 2GB 的作业,我在 while 循环中花费了大约 40 秒来迭代请求的每个部分,如果你问我的话,这已经很多了……使用 memoryStream 是 6 秒。

这种行为正常吗?是否有机会使用 MimeKit 获得更好的时间,或者我应该实现自己的解析器?

提前致谢!

【问题讨论】:

【参考方案1】:

这里有趣的是,在我使用fileStream之前,我们曾经复制过一个HttpListenerRequest对象的inputStream,这是一个无法加载到MimeKit的NetworkStream(non-seekable)。

我不太清楚你上面的意思。你在做这样的事情吗?

var memory = new MemoryStream ();
httpResponse.Stream.CopyTo (memory);
memory.Position = 0;
var message = MimeMessage.Load(memory, true);

自从添加了 fileStream,对于一个 2GB 的作业,我在 while 循环中花费了大约 40 秒来迭代请求的每个部分,如果你问我,这已经很多了......使用 memoryStream 是 6 秒。

您对MimeMessage.Load() 的使用将true 作为persistent 参数传递。这提高了 解析 性能(因为它不再需要在解析后将 MIME 内容加载到 RAM 中),但会对稍后读取单个 MIME 部分内容的性能产生负面影响,因为它需要寻找 _fileStream根据您的请求,每个 MIME 部分的内容的起始偏移量。

这种行为正常吗?

40 秒确实看起来很多,但在不了解您的代码的更多细节的情况下,我无法提出任何建议。

是否有机会使用 MimeKit 获得更好的时间,或者我应该实现自己的解析器?

好吧,我几乎可以保证,如果您实现自己的解析器,它很可能会比 MimeKit 慢几个数量级(看到在 C# 中编写 MIME 解析器的所有其他尝试实际上都比 MimeKit 慢几个数量级MimeKit) ;-)

您需要在这里做的是在分析器下运行您的代码以查看问题出在哪里。

如果性能问题如您在循环内部所建议的那样,则它不是解析器中的性能问题。这是循环中的性能问题。这并不是说 MimeKit 代码不会导致缓慢。

如果问题出在 MimeKit 中,我会怀疑 BoundStream.Read() 内部的这种逻辑:

// make sure that the source stream is in the expected position
if (BaseStream.Position != StartBoundary + position)
    BaseStream.Seek (StartBoundary + position, SeekOrigin.Begin);

在您的情况下,BaseStream 应该是您的_fileStream。自从我查看 FileStream.Position 的代码以来已经有一段时间了,但它可能需要一个系统调用来获取该值(并且系统调用不是免费的)。

但是,40 秒是很多时间 - 比我预期的要多,除非每个 MIME 部分的内容都很庞大(MimePart.Content 的流式内容每个循环读取约 4K 并且如果每个循环有 1 个 lseek()循环,可以加起来)。

希望能帮助你解决这个问题。

【讨论】:

您好,我使用分析器进行了一些额外的调试,以了解究竟发生了什么。我确实设法解决了一些问题,这些问题来自我在循环中运行的代码。修复这些后,我对结果很满意,但在执行 DecodeTo 方法时发现了一些零星的行为...... 相同的 2GB 文件有时会在 30 秒以下解码,有时会在 60 秒以上解码...我无法解决导致此问题如此不稳定的问题。这是一个已知问题还是我做错了什么?每次我使用 DecodeTo 都是将数据解码为文件流并将其保存到磁盘。感谢您迄今为止的帮助。 副手,我不确定是什么原因导致的(就 MimeKit 中的代码而言)。 2GB 是很多数据,可能只是由于内核空间切换。我很想知道您是否能够进一步调试并弄清楚发生了什么。 @jsteadfast 最近几天我一直在调试,我唯一设法找到的是超过 10GB 的高速缓存内存并且会降低性能。我注意到最适合我的是使用 Open 而不是 DecodeTo 并执行类似 Open.CopyTo 的操作。据您所知,使用 Open 是否安全? 我以为我已经对此做出了回应,但显然我没有。是的,使用Open() 代替DecodeTo() 是安全的。不过,我不明白它如何/为什么会有所作为。

以上是关于带有 FileStreams 的 MimeKit 迭代器的主要内容,如果未能解决你的问题,请参考以下文章

MimeKit:如何嵌入图像?

使用 Mailkit 和 Mimekit 收集 SMTP 服务器

导航 MimeKit.MimeParser

使用 MimeKit/MailKit 进行内容编码

无法使用 MimeKit 解密 p7m

MimeKit 附件正文编码问题