2010-08-18 20 views
6

Tengo un gran conjunto de archivos binarios donde miles de marcos de video sin formato se están leyendo y procesando secuencialmente, y ahora estoy buscando optimizarlo ya que parece estar más vinculado a la CPU que enlazado a E/S..NET Binary File Read Performance

Los marcos se están leyendo actualmente de esta manera, y sospecho que este es el mayor culpable:

private byte[] frameBuf; 
BinaryReader binRead = new BinaryReader(FS); 

// Initialize a new buffer of sizeof(frame) 
frameBuf = new byte[VARIABLE_BUFFER_SIZE]; 
//Read sizeof(frame) bytes from the file 
frameBuf = binRead.ReadBytes(VARIABLE_BUFFER_SIZE); 

¿Sería hacer mucha diferencia en .NET para volver a organizar el I/O para evitar creando todos estos nuevos arrays de bytes con cada cuadro?

Mi comprensión del mecanismo de asignación de memoria de .NET es débil ya que provengo de un fondo puro de C/C++. Mi idea es volver a escribir esto para compartir una clase de búfer estática que contiene un búfer compartido muy grande con un entero que hace un seguimiento del tamaño real del marco, pero me encanta la simplicidad y legibilidad de la implementación actual y preferiría mantenerla si el CLR ya maneja esto de alguna manera que no conozco.

Cualquier entrada sería muy apreciada.

+5

¿Ha ejecutado un generador de perfiles para asegurarse de que el rendimiento no proviene de otras fuentes? ¿O simplemente fue y asumió "Entonces, eso es probablemente"? –

+0

Hola David, Ejecuto el perfilador de rendimiento unas pocas veces y este método en particular es el más caro. Por lo tanto, estoy buscando para ver si este método de "nuevo byte []" es un asesino de rendimiento obvio en .NET. Como programador en C, esto parece análogo a miles de declaraciones "malloc" para cada buffer, que definitivamente sería más lento que un buffer reutilizado. – rnd

Respuesta

7

No necesita iniciar frameBuf si usa binRead.ReadBytes - obtendrá una nueva matriz de bytes que sobrescribirá la que acaba de crear. Sin embargo, esto crea una nueva matriz para cada lectura.

Si desea evitar crear un conjunto de matrices de bytes, puede usar binRead.Read, que colocará los bytes en una matriz que le proporcione. Sin embargo, si otros hilos están usando la matriz, verán que el contenido cambia justo en frente de ellos. Asegúrate de que puedes garantizar que termines con el buffer antes de reutilizarlo.

+0

Gracias por señalar esto. Estoy seguro de que mi asignación redundante está ralentizando esto considerablemente.Y la matriz estática compartida es exactamente lo que estoy considerando, pero si la ganancia de rendimiento no es grande en comparación con la creación de las matrices de bytes, preferiría quedarme con la solución elegante para la misma complicación que describe (acceso compartido) . – rnd

1

Debe tener cuidado aquí. Es muy fácil obtener resultados de prueba completamente falsos en códigos como este, resultados que nunca se reproducen en el uso real. El problema es la memoria caché del sistema de archivos, que almacenará en caché los datos que usted lee de un archivo. El problema comienza cuando ejecuta su prueba una y otra vez, modificando el código y buscando mejoras.

La segunda y las siguientes veces que ejecuta la prueba, los datos ya no salen del disco. Todavía está presente en la memoria caché, solo se necesita una copia de memoria a memoria para acceder a su programa. Eso es muy rápido, un microsegundo más o menos por encima del tiempo necesario para copiar. Que se ejecuta a velocidades de bus, al menos 5 gigabytes por segundo en máquinas modernas.

Su prueba ahora revelará que dedica mucho tiempo a asignar el búfer y procesar los datos, en relación con el tiempo dedicado a leer los datos.

Esto rara vez reproducirá en el uso real. Los datos aún no estarán en la memoria caché, ahora la unidad de disco sluggy necesita buscar los datos (muchos milisegundos) y debe leerse en la bandeja del disco (un par de docenas de megabytes por segundo, en el mejor de los casos). Leer los datos ahora toma tres o cuatro magnitudes de tiempo más. Si lograste hacer el paso de procesamiento el doble de rápido, tu programa solo funcionará un 0.05% más rápido. Da o toma.

+0

Ese es un buen punto, sin embargo, estoy ejecutando mis pruebas en un conjunto de datos que empequeñece la memoria de mi máquina en varios gigabytes. Lo que me preocupa es el hecho de que un código similar en mi antigua biblioteca C++ procesaría este conjunto de datos en menos de la mitad del tiempo que esto lleva. Sin embargo, me di cuenta de que el perfil advierte que se escriben aproximadamente 2.826 páginas por/s en el disco y que la aplicación puede estar en memoria. No me deshago explícitamente de ninguno de estos arreglos: ¿podrían almacenarse en caché antes de que el GC los desasigne? – rnd

+2

Estos búferes son probablemente grandes, más de 85 KB. Lo cual los asigna en el LOH. Estarán atrapados allí por un tiempo, se necesita una colección gen # 2. Nada viene gratis, la reutilización de almacenamientos intermedios cuando son grandes también es una buena estrategia en .NET. –

+0

Si desea forzar que el archivo se cargue desde el disco, borre la caché de archivos de Windows, como se ve en esta pregunta: http://stackoverflow.com/q/478340/80525 – BKewl