适用于.NET的最快PNG解码器

时间:2012-07-03 14:35:55

标签: c# performance png decode decoding

我们的Web服务器需要在将结果发送到Web客户端之前将多个大型图像组合在一起。此过程对性能至关重要,因为服务器每小时可以收到数千个请求。

现在我们的解决方案从HD加载PNG文件(每个大约1MB)并将它们发送到视频卡,以便在GPU上完成合成。我们首先尝试使用XNA API公开的PNG解码器加载我们的图像。我们看到表现不太好。

要了解问题是从HD加载还是解码PNG,我们通过将文件加载到内存流中,然后将该内存流发送到.NET PNG解码器来修改它。使用XNA或使用System.Windows.Media.Imaging.PngBitmapDecoder类的性能差异并不重要。我们大致得到了相同的性能水平。

我们的基准测试显示以下表现结果:

  • 从磁盘加载图像:37.76ms 1%
  • 解码PNG:2816.97ms 77%
  • 在视频硬件上加载图像:196.67ms 5%
  • 成分:87.80ms 2%
  • 从视频硬件获取合成结果:166.21ms 5%
  • 编码为PNG:318.13ms 9%
  • 存储到磁盘:3.96ms 0%
  • 清理:53.00ms 1%

总计:3680.50ms 100%

根据这些结果,我们看到解码PNG时最慢的部分。

所以我们想知道是否会有一个我们可以使用的PNG解码器,这将允许我们减少PNG解码时间。我们还考虑将图像保持在硬盘上不压缩,但是每个图像的大小为10MB而不是1MB,并且由于硬盘上存储了数万个这样的图像,因此无法存储它们。压缩。

编辑:更有用的信息:

  • 基准测试模拟加载20个PNG图像并将它们合成在一起。这大致对应于我们将在生产环境中获得的请求类型。
  • 合成中使用的每张图片尺寸为1600x1600。
  • 解决方案将涉及多达10个负载平衡服务器,就像我们在这里讨论的那样。因此,额外的软件开发工作可能值得节省硬件成本。
  • 我们正在考虑缓存已解码的源图像,但每种组合很可能使用完全不同的源图像完成,因此缓存未命中率高,性能提升低。
  • 基准测试是用一块糟糕的视频卡完成的,所以我们可以期待使用体面的视频卡将PNG解码更加成为性能瓶颈。

4 个答案:

答案 0 :(得分:6)

还有另一种选择。也就是说,您编写自己的基于GPU的PNG解码器。您可以使用OpenCL来相当有效地执行此操作(并使用可与OpenCL共享资源的OpenGL执行组合)。还可以交错传输和解码以获得最大吞吐量。如果这是您可以/想要追求的路线,我可以提供更多信息。

以下是与基于GPU的DEFLATE(和INFLATE)相关的一些资源。

  1. Accelerating Lossless compression with GPUs
  2. gpu-block-compression在Google代码上使用CUDA。
  3. Floating point data-compression at 75 Gb/s on a GPU - 请注意,这不是使用INFLATE / DEFLATE,而是一种新的并行压缩/解压缩方案,它更适合GPU。
  4. 希望这有帮助!

答案 1 :(得分:4)

你有没有尝试过以下两件事。

1)
多线程它,有几种方法可以做到这一点,但一种方法是“全进”方法。基本上完全生成X线程数量,用于完整过程。

2)
也许考虑让XX线程完成所有CPU工作,然后将其提供给GPU线程。

您的问题非常适合作为新用户,但有关Senario的一些信息可能有用吗? 我们是在实时谈论批量作业还是服务图片? 10k图片会改变吗?

硬件资源
您还应该考虑到您所拥有的硬件资源。 Normaly最便宜的两件事就是CPU电源和磁盘空间,所以如果你只有10k的图片可以轻易改变,那么将它们全部转换成一种更快速处理的格式可能就是这样。

多线程琐事
在进行多线程处理时要考虑的另一件事是,使用BellowNormal优先级的线程是非常聪明的。所以你不要让整个系统“滞后”。你必须尝试使用​​一定数量的线程,如果运气好,你可以获得接近100%的速度pr CORE增益,但这取决于你运行的硬件和代码。

我正式使用Environment.ProcessorCount来获取当前的CPU数量并从那里开始工作:)

答案 2 :(得分:2)

你有多个选项

  • 提高解码过程的性能

    你可以实现另一个更快的png解码器 (libpng是一个可能更快的标准库) 您可以切换到使用更简单/更快的可解码压缩的另一种图片格式

  • 并行化

    使用.NET并行处理功能进行并发解码。解码可能是单线程的,因此如果您在多核计算机上运行,​​这可能会有所帮助

  • 将文件解压缩但存储在压缩设备上

    例如压缩文件夹甚至是sandforce ssd。 这仍然会压缩但不同并且减轻了其他软件的负担。我不确定这会有什么帮助,只会尝试这个作为最后的手段。

答案 3 :(得分:2)

我写了一个纯C#PNG编码器/解码器(PngCs),你可能想看看。 但我非常怀疑它会有更好的速度[*],它没有高度优化,而是试图最小化处理大图像的内存使用(它按顺序逐行编码/解码)。但也许它可以作为样板来插入一些更好的压缩/解压缩实现。正如我所看到的,速度瓶颈是zlib(inflater / deflater),它(与Java相反)并没有在C#本地实现 - 我使用了SharpZipLib库,使用纯C#托管代码;这不是非常有效。

然而,我有点惊讶,在你的测试中,解码比编码慢得多。这对我来说似乎很奇怪,因为在大多数压缩算法中(可能在所有;并且肯定在zlib中)编码比解码更加计算机密集。 你确定吗? (例如,这个speedtest读取和写入5000x5000 RGB8图像(不是非常可压缩,磁盘上大约20MB)给了我大约4.5秒的写入时间和1.5秒的读取时间。除了纯PNG解码外,还有其他因素吗?

[*]更新:有多个优化的新版本(自1.1.14开始);如果你可以使用.Net 4.5,特别是它应该提供更好的解码速度。