27

在将结果发送到 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

4 回答 4

6

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

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

  1. 使用 GPU 加速无损压缩
  2. 在 Google 代码上使用 CUDA 进行gpu-block-compression 。
  3. 在 GPU 上以 75 Gb/s 的速度进行浮点数据压缩- 请注意,这不使用 INFLATE/DEFLATE,而是一种对 GPU 更友好的新型并行压缩/解压缩方案。

希望这可以帮助!

于 2012-07-03T14:57:41.750 回答
4

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

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

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

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

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

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

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

于 2012-07-03T14:51:18.103 回答
3

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

但是,我有点惊讶,在您的测试中,解码比编码慢得多。这对我来说似乎很奇怪,因为在大多数压缩算法中(也许是全部;当然在 zlib 中)编码比解码更需要计算机密集。您确定吗?(例如,这个读写 5000x5000 RGB8 图像的速度测试(不是很可压缩,磁盘上大约 20MB)给了我大约 4.5 秒的写入时间和 1.5 秒的读取时间)除了纯PNG解码之外,也许还有其他因素?

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

于 2012-07-03T23:15:15.900 回答
2

您有多种选择

  • 提高解码过程的性能

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

  • 并行化

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

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

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

于 2012-07-03T15:44:51.547 回答