c# performance png decode decoding

c# - El decodificador PNG más rápido para.NET



performance decode (4)

Nuestro servidor web necesita procesar muchas composiciones de imágenes grandes juntas antes de enviar los resultados a los clientes web. Este proceso es crítico para el rendimiento porque el servidor puede recibir varios miles de solicitudes por hora.

En este momento, nuestra solución carga archivos PNG (aproximadamente 1 MB cada uno) desde el disco duro y los envía a la tarjeta de video para que la composición se realice en la GPU. Primero intentamos cargar nuestras imágenes usando el decodificador PNG expuesto por la API XNA. Vimos que el rendimiento no era demasiado bueno.

Para comprender si el problema se estaba cargando desde el HD o la decodificación del PNG, lo modificamos cargando el archivo en una secuencia de memoria y luego enviando esa secuencia de memoria al decodificador .NET PNG. La diferencia de rendimiento al utilizar XNA o usar la clase System.Windows.Media.Imaging.PngBitmapDecoder no es significativa. Aproximadamente tenemos los mismos niveles de rendimiento.

Nuestros puntos de referencia muestran los siguientes resultados de rendimiento:

  • Cargar imágenes desde disco: 37.76ms 1%
  • Decodificar PNGs: 2816.97ms 77%
  • Cargar imágenes en Video Hardware: 196.67ms 5%
  • Composición: 87.80ms 2%.
  • Obtenga el resultado de la composición del hardware de video: 166.21ms 5%
  • Codificar a PNG: 318.13ms 9%
  • Almacenar en disco: 3.96ms 0%
  • Limpieza: 53.00ms 1%.

Total: 3680.50ms 100%

De estos resultados vemos que las partes más lentas son cuando se decodifica el PNG.

Así que nos preguntamos si no habría un decodificador PNG que pudiéramos usar que nos permita reducir el tiempo de decodificación PNG. También consideramos mantener las imágenes sin comprimir en el disco duro, pero luego cada imagen tendría un tamaño de 10 MB en lugar de 1 MB y, dado que hay varias decenas de miles de estas imágenes almacenadas en el disco duro, no es posible almacenarlas todas sin compresión.

EDITAR: Más información útil:

  • El punto de referencia simula la carga de 20 imágenes PNG y su composición. Esto corresponderá aproximadamente al tipo de solicitudes que recibiremos en el entorno de producción.
  • Cada imagen utilizada en la composición tiene un tamaño de 1600x1600.
  • La solución incluirá hasta 10 servidores con carga equilibrada como el que estamos discutiendo aquí. Por lo tanto, un esfuerzo adicional de desarrollo de software podría valer los ahorros en costos de hardware.
  • El almacenamiento en caché de las imágenes de origen descodificadas es algo que estamos considerando, pero lo más probable es que cada composición se realice con imágenes de origen completamente diferentes, por lo que las fallas de caché serán altas y la ganancia de rendimiento será baja.
  • Los puntos de referencia se realizaron con una tarjeta de video de mala calidad, por lo que podemos esperar que la decodificación PNG sea aún más un cuello de botella de rendimiento al usar una tarjeta de video decente.

¿Has probado las 2 cosas siguientes?

1)
Hilo múltiple, hay varias formas de hacer esto, pero una sería un método "todo en". Básicamente genera totalmente X cantidad de hilos, para el proceso completo.

2)
Tal vez considere que el subproceso XX haga todo el trabajo de la CPU y luego aliméntelo al subproceso de la GPU.

Su pregunta está muy bien formulada para ser un nuevo usuario, pero ¿alguna información sobre el senario podría ser útil? ¿Estamos hablando de un trabajo por lotes o imágenes de servicio en tiempo real? ¿Cambian las fotos de 10k?

Recursos de hardware
También debe tener en cuenta qué recursos de hardware tiene a su disposición. Normalmente, las 2 cosas más baratas son la potencia de la CPU y el espacio en el disco, por lo que si solo tienes 10k imágenes que cambian raramente, convertirlas todas en un formato que sea más rápido de manejar podría ser el camino a seguir.

Trivias multihilo
Otra cosa a tener en cuenta al realizar subprocesos múltiples, es que normalmente es inteligente hacer que los subprocesos tengan prioridad BellowNormal. Por lo tanto, no debe hacer que todo el sistema se "retrase". Tienes que experimentar un poco con la cantidad de subprocesos que debes usar, si tienes suerte, puedes obtener una ganancia cercana al 100% en la velocidad de CORE, pero esto depende mucho del hardware y del código que ejecutes.

Normalmente uso Environment.ProcessorCount para obtener el recuento actual de CPU y trabajar desde allí :)


Hay otra opción. Y eso es, usted escribe su propio decodificador PNG basado en GPU. Podría usar OpenCL para realizar esta operación de manera bastante eficiente (y realizar su composición usando OpenGL que puede compartir recursos con OpenCL). También es posible intercalar la transferencia y la decodificación para obtener el máximo rendimiento. Si esta es una ruta que puede / desea seguir, puedo proporcionarle más información.

Aquí hay algunos recursos relacionados con DEFLATE (e INFLATE) basado en GPU.

  1. Aceleración de la compresión sin pérdida con GPUs
  2. gpu-block-compression usando CUDA en el código de Google.
  3. Compresión de datos de punto flotante a 75 Gb / s en una GPU : tenga en cuenta que esto no utiliza INFLATE / DEFLATE, sino un nuevo esquema de compresión / descompresión en paralelo que es más compatible con GPU.

¡Espero que esto ayude!


He escrito un codificador / decodificador C # PNG puro ( PngCs ), es posible que desee darle un vistazo. Pero dudo mucho que tenga una mejor velocidad [*], no está altamente optimizada, sino que trata de minimizar el uso de la memoria para tratar con imágenes grandes (se codifica / decodifica secuencialmente, línea por línea). Pero quizás le sirva como repetitivo para conectar alguna mejor implementación de compresión / descompresión. Como lo veo, el cuello de botella de la velocidad es zlib (inflater / deflater), que (contrariamente a Java) no se implementa de forma nativa en C #; usé una biblioteca SharpZipLib, con código administrado puro de C #; Esto no puede ser muy eficiente.

Sin embargo, estoy un poco sorprendido de que en tus pruebas la decodificación fuera mucho más lenta que la codificación. Eso me parece extraño, porque en la mayoría de los algoritmos de compresión (quizás en todos; y seguramente en zlib) la codificación requiere mucho más computación que la descodificación. ¿Estás seguro de eso? (Por ejemplo, esta speedtest que lee y escribe imágenes de 5000x5000 RGB8 (no muy compresible, aproximadamente 20MB en el disco) me da aproximadamente 4.5 segundos para escribir y 1.5 segundos para leer). ¿Quizás hay otro factor aparte de la decodificación PNG pura?

[*] Actualización: nuevas versiones (desde 1.1.14) que tienen varias optimizaciones; Si puede usar .Net 4.5, especialmente, debería proporcionar una mejor velocidad de decodificación.


Tienes opciones mutliple

  • Mejorar el rendimiento del proceso de decodificación.

    Podría implementar otro decodificador png más rápido (libpng es una biblioteca estándar que podría ser más rápida) Podría cambiar a otro formato de imagen que use una compresión decodificable más simple / más rápida

  • Paralelizar

    Utilice las capacidades de procesamiento paralelo de .NET para decodificar simultáneamente. Es probable que la decodificación sea de un solo hilo, por lo que esto podría ayudar si se ejecuta en máquinas multinúcleo

  • Almacena los archivos sin comprimir pero en un dispositivo que comprime

    Por ejemplo, una carpeta comprimida o incluso un ssd sandforce. Esto seguirá comprimiendo pero de manera diferente y cargará a otros programas con la descompresión. No estoy seguro de que esto realmente ayude y solo lo intentaría como último recurso.