【问题标题】:Fastest PNG decoder for .NET.NET 上最快的 PNG 解码器
【发布时间】:2012-07-04 00:33:08
【问题描述】:

我们的网络服务器需要一起处理许多大图像的组合,然后再将结果发送给网络客户端。此过程对性能至关重要,因为服务器每小时可以接收数千个请求。

现在,我们的解决方案从 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 解码使用像样的显卡会成为更大的性能瓶颈。

【问题讨论】:

  • +1 用于实际分析
  • 您是否尝试过不同的 PNG 编码以查看对性能的影响(隔行扫描、24 位、效率较低的压缩)
  • @sboisse 另一种选择是缓存未压缩的图像。我会统计一下使用了哪些图像以及何时使用,然后检查缓存命中率。如果你为磁盘上的缓存分配了 10 GB 的空间,那就是 1,000 个图像。
  • 我会将图像存储为二进制、预解码的文件,您可以立即加载并提供给 GPU。如果它们每个占用 10MB,那么每 TB 可以存储近 100,000 个(我修正了我的数学)
  • @sboisse 我没有说缓存作品,而是解码后的源图像(最慢的步骤)。完全按照亚历克斯的建议。

标签: c# performance png decode decoding


【解决方案1】:

还有另一种选择。也就是说,您编写自己的基于 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 更友好。

希望这会有所帮助!

【讨论】:

  • 这可行吗?我在阅读问题时尝试过,但谷歌没有找到任何我能找到的参考。
  • 另请注意 - 这是一个发球。具有良好 GPU 的服务器很少见,而服务器级卡则非常昂贵。可能是 Web 服务器图像处理的死胡同。
  • @TomTom:谁说服务器级卡很贵?您不需要“工作站卡”。普通的消费卡可以正常工作。我实习的最后一个地方在他们的生产服务器中使用了一组消费者 GPU。
  • 啊,是的。尝试将其安装在典型的托管级别服务器中。如果您去购买/租用服务器,则不能放入典型的卡,除非功率低-您必须正确选择硬件。开始时 1u 非常小,而 2U 服务器没有高端显卡的电源。是的,您为此构建了 dservers - 我在另一个房间里有几个 Quad 6990 进行波动率计算。但是看看服务器供应商并尝试将 GPU 安装到机架式服务器中,您很快就会感到沮丧。
  • @TomTom 我们理解您的观点,但 OP 表示如果确实有益,这是可能的。
【解决方案2】:

您是否尝试过以下 2 件事。

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

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

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

硬件资源
您还应该考虑您拥有哪些硬件资源。 通常,最便宜的两件事是 CPU 功率和磁盘空间,因此,如果您只有 10k 张很少更改的图片,那么将它们全部转换为更快处理的格式可能是可行的方法。

多线程琐事
进行多线程时要考虑的另一件事是,使线程处于 BellowNormal 优先级通常很聪明。所以你不会让整个系统“滞后”。您必须对要使用的线程数量进行一些试验,如果运气好的话,您可以获得接近 100% 的速度提升 pr CORE,但这在很大程度上取决于硬件和您运行的代码。

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

【讨论】:

  • 我不懂游戏引擎cmets。鉴于“我们的网络服务器需要一起处理许多大图像的组合,然后再将结果发送到网络客户端”
  • 评论建议游戏,但请记住。我们是在谈论实时提供图片吗?或某种批处理作业:)。如果它是一个批处理作业缓存可能没有用。但实时缓存是一个巨大的优势
  • @EKS cmets 明确声明这不是为了游戏:@user1260028: this is not a game. It is a webserver that must do many image compositions to be sent to web browsers. 我确实意识到你在写评论之前就发布了你的答案。
  • 这是个好主意,但这确实是多线程只是一个拐杖的情况之一,实际问题是底层算法。使用的解码器可能不是最理想的,在这种情况下,您不应该期望多线程只会让事情变得更好。
  • 啊,不。有时需要暴力破解。一个像样的 AMD 服务器可以为您提供 32 个内核以比考虑问题更少的钱工作,排队机制可以在网格类型环境中运行任意数量的作曲家。有些问题只能靠蛮力解决。
【解决方案3】:

我编写了一个纯 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,特别是它应该提供更好的解码速度。

【讨论】:

  • 我认为解码比编码长,因为代码正在解码 100 张图像,但只编码 1。
  • 确实joocer是对的,因为我们的测试加载了20张源图像,但合成完成后只生成一张,因此解码时间比编码时间长。
  • 啊,有道理,抱歉
【解决方案4】:

你有多种选择

  • 提高解码过程的性能

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

  • 并行化

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

  • 将未压缩的文件存储在可压缩的设备上

    例如一个压缩文件夹,甚至是一个沙力 SSD。 这仍然会压缩,但会有所不同,并且会因解压缩而加重其他软件的负担。我不确定这是否真的有帮助,并且只能作为最后的手段尝试。

【讨论】:

  • 我们可以预期并行化可以改善解码时间,但由于在高峰时间每秒发出许多请求,因此服务器每秒处理的请求数量应该相同。多线程将在请求级别而不是在解码级别进行。
  • 我们将看看 libpng 并看看它是如何进行的。使用其他一些无损图像格式可能是一个有趣的选择。有什么格式可以推荐吗?
  • 并非如此。我找不到太多关于图片格式之间相对解压缩时间的信息。对于 JPG,这里有一个有趣的比较,它显示了最慢和最快解码器之间的 10 倍差异...briancbecker.com/blog/2010/analysis-of-jpeg-decoding-speeds
  • BMP 文件的加载速度比 PNG 文件快得多,即使 BMP 文件要大得多。
猜你喜欢
  • 1970-01-01
  • 2011-03-21
  • 2011-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多