2009-07-29 8 views
11

He creado una aplicación que hace lo siguiente:¿Cuántos archivos pequeños o uno grande? (O, sobrecarga de abrir y cerrar el archivo asas) (C++)

  1. Hacer algunos cálculos, escritura datos calculados a un archivo - Repita para 500.000 veces (sobre todo, escriba 500,000 archivos uno después del otro) - repita 2 veces más (sobre todo, se escribieron 1,5 millones de archivos).
  2. Leer datos de un archivo, hacer algunos cálculos intensos con los datos del archivo - para repetir 1.500.000 iteraciones (iterar sobre todos los archivos escritos en el paso 1.)
  3. repita el paso 2 por 200 iteraciones.

Cada archivo es ~ 212k, así que sobre todo tengo ~ 300Gb de datos. Parece que todo el proceso lleva ~ 40 días en una CPU Core 2 Duo con 2.8 Ghz.

Mi problema es (como probablemente puede adivinar) es el tiempo que lleva completar todo el proceso. Todos los cálculos son en serie (cada cálculo depende del anterior), por lo que no puedo realizar un paralelo de este proceso con diferentes CPU o PC. Estoy tratando de pensar cómo hacer que el proceso sea más eficiente y estoy bastante seguro de que la mayor parte de la sobrecarga va al acceso al sistema de archivos (duh ...). Cada vez que accedo a un archivo, le abro un identificador y luego lo cierro una vez que termino de leer los datos.

Una de mis ideas para mejorar el tiempo de ejecución era usar un archivo grande de 300Gb (o varios archivos grandes de 50Gb cada uno), y luego solo usaría un archivo abierto y simplemente buscaría cada dato relevante y leería pero no soy el responsable de abrir y cerrar los identificadores de archivo. ¿Alguien puede arrojar algo de luz sobre esto?

Otra idea que tuve fue intentar agrupar los archivos en archivos ~ 100Mb más grandes y luego leería 100Mb cada vez en lugar de muchas lecturas de 212k, pero esto es mucho más complicado de implementar que la idea anterior.

De todos modos, si alguien puede darme algún consejo sobre esto o tiene alguna idea de cómo mejorar el tiempo de ejecución, ¡lo agradecería!

Gracias.

actualización de perfiles:

Me corrió un generador de perfiles en el proceso, parece que los cálculos tienen el 62% de tiempo de ejecución y la lectura de archivos se realiza el 34%. Lo que significa que incluso si recorté milagrosamente los costos de E/S de archivo por un factor de 34, aún me quedan 24 días, lo cual es una gran mejora, pero todavía mucho tiempo :)

+0

¿Ha considerado almacenarlo en una base de datos? –

+1

Lo he considerado, pero ¿eso haría que la extracción de datos fuera más rápida? – dudico

+0

Has dicho que estás bastante seguro de que abrir/cerrar los archivos es un cuello de botella. ¿Es esto una corazonada basada en perfilar el programa o es más bien una corazonada general? Si es lo último, te sugiero que primero perfile tu código. –

Respuesta

9

Cómo abrir un identificador de archivo isn ' t probable ser el cuello de botella; el disco real IO es. Si puede paralelizar el acceso al disco (por ejemplo, usando múltiples discos, discos más rápidos, un disco RAM, ...) puede beneficiarse mucho más. Además, asegúrese de que IO no bloquee la aplicación: lea desde el disco y procese mientras espera IO. P.ej. con un lector y un hilo de procesador.

Otra cosa: si el siguiente paso depende del cálculo actual, ¿por qué hacer el esfuerzo de guardarlo en el disco? Tal vez con otra vista sobre las dependencias del proceso puede volver a trabajar en el flujo de datos y deshacerse de una gran cantidad de IO.

Oh sí, y medida que :)

+0

Solo guardo los datos en el primer paso y los uso en el segundo paso, debo guardar los datos en los archivos. En realidad, el consejo de usar otro hilo para leer desde el disco suena como una buena idea. – dudico

+0

"¿por qué hacer el esfuerzo de guardarlo en el disco?" Lo más probable es que no tenga 300 GB de RAM. –

+0

@onebyone: pero él * dice * confía en el resultado del paso anterior para calcular el actual, y 1 paso es aproximadamente 212kB, entonces ... – xtofl

2

El uso de archivos de memoria asignada deben ser investigados, ya que reducirá el número de llamadas al sistema.

+0

¿Como en el uso de un archivo grande que está mapeado en la memoria? – dudico

+0

No exactamente, se puede hacer para archivos cada vez más grandes, pero está limitado por el espacio máximo de direcciones de proceso (en 32 bits, alrededor de 4 GB). Necesita soporte para archivos mapeados en memoria desde el sistema operativo. Básicamente, el administrador de memoria virtual se encarga de mapear los archivos en el espacio de direcciones del proceso. En Unix esto es proporcionado por la llamada mmap y en Windows por la llamada createfilemapping. – steve

+0

Un sistema operativo de 64 bits debe poder mapear 300 MB todo en un rango de direcciones contiguas. –

9

Cada archivo es ~ 212k, así que sobre todo tengo ~ 300 Gb de datos. Parece que el proceso completo tarda ~ 40 días ... todos los cálculos son en serie (cada cálculo depende de uno antes), por lo que no puedo hacer paralelo este proceso a diferentes CPU o PC. ... bonito seguro que la mayor parte de la sobrecarga va a acceso al sistema de archivos ... Cada vez que accedo a un archivo abro un manejador y luego lo cierro una vez que termino leyendo los datos.

Escribiendo datos 300 GB de datos en serie pueden tomar 40 minutos, solo una pequeña fracción de 40 días. El rendimiento de escritura en disco no debería ser un problema aquí.

Su idea de abrir el archivo una sola vez es puntual. Probablemente cierre el archivo después de que cada operación esté bloqueando su procesamiento hasta que el disco haya escrito por completo todos los datos, anulando los beneficios del almacenamiento en caché de disco.

Mi apuesta es la implementación más rápida de esta aplicación utilizará un archivo mapeado en memoria, todos los sistemas operativos modernos tienen esta capacidad. También puede llegar a ser el código más simple. Necesitará un procesador y sistema operativo de 64 bits, debe no necesita 300 GB de RAM. Ubique todo el archivo en el espacio de direcciones a la vez y solo lea y escriba sus datos con punteros.

+0

300 GB durante 40 días equivale a 5 MB por minuto. – Pacerier

4

Antes de realizar cambios, puede ser útil ejecutar un seguimiento del generador de perfiles para determinar dónde se gasta la mayor parte del tiempo para asegurarse de que realmente se optimiza el problema real.

4

¿Qué hay de usar SQLite? Creo que puedes salir con una sola mesa.

+1

Lo he considerado, pero ¿eso haría que la extracción de datos fuera más rápida? – dudico

+0

Más rápido significa ¿cuánto? No creo que sea más lento. Considere la sobrecarga de abrir y cerrar miles de archivos o buscar información en un único archivo grande. Al usar SQLite obtienes un solo archivo, optimizado con indexación. Además, SQLite admite bases de datos en memoria. Eso significa que puede almacenar en caché parte de sus datos para un acceso más rápido, sin escribir un código nuevo para eso. –

+1

No necesito indexación porque sabré el desplazamiento exacto desde el principio del archivo. El almacenamiento en caché puede ayudar, pero eso depende de la implementación de la caché. – dudico

3

De su breve explicación parece que la sugerencia xtofl de hilos es la forma correcta de proceder. Sin embargo, recomendaría que primero perfile su aplicación para asegurarse de que el tiempo se divide entre IO y CPU.

Entonces consideraría tres hilos unidos por dos colas.

  1. El subproceso 1 lee los archivos y los carga en ram, luego coloca los datos/punteros en la cola. Si la cola supera un determinado tamaño, el hilo duerme, si está por debajo de un cierto tamaño si se inicia nuevamente.
  2. Tema 2 lee los datos de la cola y hace los cálculos y luego escribe los datos en la segunda cola
  3. Tema 3 lee la segunda cola y escribe los datos en el disco

Se podría considerar la fusión de hilo 1 y 3, esto podría reducir la contención en el disco ya que su aplicación solo haría una operación de disco a la vez.

Además, ¿cómo maneja el sistema operativo todos los archivos? ¿Están todos en un solo directorio? ¿Cómo es el rendimiento cuando navegas por el directorio (gui filemanager/dir/ls)? Si este rendimiento es malo, es posible que esté trabajando fuera de la zona de confort de su sistema de archivos. Aunque solo podía cambiar esto en Unix, algunos sistemas de archivos están optimizados para diferentes tipos de uso de archivos, por ejemplo, archivos grandes, muchos archivos pequeños, etc. También podría considerar dividir los archivos en diferentes directorios.

Cuestiones relacionadas