¿Cuál es la mejor manera de escribir a más archivos que permite que el núcleo abierto a la vez?

StackOverflow https://stackoverflow.com/questions/3054892

Pregunta

Tengo un archivo binario muy grande y tengo que crear archivos separados en base a la ID en el archivo de entrada. Hay 146 archivos de salida y estoy utilizando cstdlib y fopen y fwrite. FOPEN_MAX es 20, así que no puedo guardar todos los archivos de salida 146 se abren al mismo tiempo. También quiero minimizar el número de veces que se abren y cierran un archivo de salida.

¿Cómo puedo escribir en los archivos de salida de manera efectiva?

También debe utilizar la biblioteca cstdlib debido al código heredado.

El mosto ejecutable también ser Unix y Windows compatibles con cualquier plataforma.

¿Fue útil?

Solución

Un par posibles enfoques que puede tomar:

  • mantener una caché de manejadores de archivos abiertos de salida que es menos de FOPEN_MAX - si una escritura necesidades que se produzcan en un archivos que ya está abierto, a continuación, sólo hacen la escritura. De lo contrario, cerca de uno de los controladores en la memoria caché y abrir el archivo de salida. Si los datos se agruparon en general, en función de los datos para un determinado conjunto de archivos se agrupan en el archivo de entrada, esto debería funcionar bien con una política LRU para la caché de identificador de archivo.

  • admitir la salida de amortiguar a sí mismo en lugar de dejar la biblioteca que lo haga por usted: mantener su propio conjunto de 146 (o como muchos lo que pueda necesitar) buffers de salida y amortiguar la salida a aquellos, y llevar a cabo un / ras abiertas / cierre cuando un búfer de salida particular, se llena. Incluso se puede combinar esto con el enfoque de arriba para realmente reducir al mínimo las operaciones de apertura / cierre.

Sólo asegúrese de probar bien para las condiciones de borde que pueden suceder en llenar o casi llenar un búfer de salida.

Otros consejos

También puede valer la pena escanear el archivo de entrada, hacer una lista de cada uno Identificación del producto y la clasificación de manera que se escribe todas las entradas fichero1 primero, y luego todo el archivo 2 entradas, etc ..

Si no se puede aumentar al máximo FOPEN_MAX alguna manera, se puede crear una cola de solicitudes y sencilla continuación, cierre y vuelva a abrir archivos según sea necesario.

También puede realizar un seguimiento de la última escritura en tiempo para cada archivo, y tratar de mantener los archivos escritos más recientemente abierta.

La solución parece obvia - N archivos abiertos, donde N es algo menor que FOPEN_MAX. A continuación, lea a través del archivo de entrada y extraer el contenido de los primeros archivos de salida N. A continuación, cierre los archivos de salida, rebobinar la entrada, y repetir.

En primer lugar, espero que se ejecuta tanto en paralelo como sea posible. No hay ninguna razón por la que no se puede escribir en varios archivos al mismo tiempo. Yo recomiendo hacer lo ThomasK dicho y solicitudes de cola. A continuación, puede utilizar un poco de sincronización de subprocesos que esperar hasta que toda la cola se vacía antes de permitir que la próxima ronda de escrituras que pasar.

Usted no ha mencionado si es crítica para escribir en estas salidas en "tiempo real", o la cantidad de datos que se está escribiendo. Con sujeción a sus limitaciones, una opción podría ser la de amortiguar todas las salidas y escribirlos al final de su software de correr.

Una variante de esto es búferes internos de instalación de un tamaño fijo, una vez que se pulsa el límite de búfer interno, abra el archivo, añadir, y cerca, a continuación, vaciar el búfer de salida para más. Los amortiguadores reducen el número de ciclos de apertura / cierre y le dan ráfagas de escrituras, que el sistema de archivos es generalmente de configuración para manejar muy bien. Esto sería para casos donde se necesita un poco de tiempo real escribe, y / o datos es más grande que la memoria disponible y los identificadores de archivo excede cierta máximo en su sistema.

Puede hacerlo en 2 pasos.

1) los primeros 19 ids a un archivo, los próximos 19 identificadores de archivo a la siguiente y así sucesivamente. Así que hay 8 archivos de salida (y el archivo de entrada) abiertos en paralelo durante este paso.

2) Por cada archivo para crear creado 19 (sólo 13 para el último) nuevos archivos y escribir los identificadores a la misma.

Independientemente de qué tan grande es el archivo de entrada y el número de id-bases de datos que contiene, siempre hay que abrir y cerrar 163 archivos. Pero hay que escribir los datos en dos ocasiones, por lo que puede sólo vale la pena, si el ID-bases de datos son muy pequeñas y distribuidas al azar.

creo que en la mayoría de los casos es más eficiente para abrir y cerrar los archivos con más frecuencia.

El método más seguro es abrir un archivo y al ras después de la escritura, a continuación, cerrar si no hay una escritura más reciente se llevará a cabo. Muchas cosas fuera de lata de control de su programa de dañar el contenido de su archivo. Tenga esto en cuenta al leer sucesivamente.

Sugiero mantener un std::map o std::vector de punteros FILE. El map que permite a los punteros de archivos de acceso de una identificación. Si el rango de ID es pequeña, se podría crear una vector, los elementos de la reserva, y el uso de la ID como un índice. Esto le permitirá mantener una gran cantidad de archivos abiertos al mismo tiempo. Cuidado con el concepto de corrupción de datos.

El límite de archivos abiertos simultáneos se establece por el sistema operativo. Por ejemplo, si su sistema operativo tiene un máximo de 10, tendrá arreglos hace cuando se solicita el archivo 11.

Otro truco es buffers de reserva en memoria dinámica para cada archivo. Cuando se procesa todos los datos, abrir un archivo (o más de uno), escribir la memoria intermedia (utilizando uno fwrite), cerca y seguir adelante. Esto puede ser más rápido, ya que está escrito en la memoria durante el procesamiento de datos en lugar de un archivo. Una nota interesante es que su sistema operativo también puede página las memorias intermedias en el disco duro también. El tamaño y la cantidad de buffers es un problema de optimización que es dependiente de la plataforma (que tendrá que ajustar y prueba para obtener una combinación bien). Su programa se ralentizará si las páginas del sistema operativo de la memoria en el disco.

Bueno, si lo estaba escribiendo con sus limitaciones enumeradas en el PO, que crearía 146 tampones y plop los datos en ellos, luego, al final, de forma secuencial caminar a través de las memorias intermedias y cerrar / abrir un único archivo de manejar.

Usted ha mencionado en un comentario de que la velocidad era una preocupación importante y que el enfoque ingenuo es demasiado lento.

Hay algunas cosas que usted puede comenzar a considerar. Se trata de una reorganización del archivo binario en tiras secuenciales, lo que permitiría operaciones paralelas. Otro es un enfoque utilizado menos recientemente a su colección gestor de archivo. Otro enfoque podría ser que desembolsar a 8 procesos diferentes, cada uno a la salida de archivos 19-20.

Algunos de estos enfoques será más o menos práctico para escribir en función de la organización binaria (muy fragmentado vs altamente secuencial).

Una limitación importante es el tamaño de los datos binarios. Es más grande que la memoria caché? más grande que la memoria? transmitido de una unidad de cinta? Continuamente viene de una corriente del sensor y sólo existe como un 'archivo' en la memoria? Cada uno de esos presentes una estrategia de optimización diferente ...

Otra cuestión es patrones de uso. ¿Estás haciendo las escrituras pico ocasionales a los archivos, o está teniendo enormes trozos escritos solamente un par de veces? Que determina la eficacia de los diferentes de almacenamiento en caché / paging estrategias de identificadores de archivo.

Suponiendo que usted está en un sistema * nix, el límite es por proceso, no en todo el sistema. Por lo que implica que podría poner en marcha varios procesos, cada uno responsable de un subconjunto del ello es que está filtrando para. Cada uno podía mantener dentro del FOPEN_MAX para su proceso.

Usted podría tener un proceso padre de leer el archivo de entrada a continuación, enviar los datos a diversos procesos de escritura '' a través de ficheros especiales de tubería.

"menor número de archivo se abre" Estrategia:

Para lograr un número mínimo de archivo abre y se cierra, se tendrá que leer a través de los múltiples tiempos entrada. Cada vez, se elige un subconjunto de los identificadores que necesitan de clasificación, y extraer sólo aquellos registros en los archivos de salida.

Pseudocódigo para cada hilo:

  1. Ejecutar a través del archivo, recoger todos los identificadores únicos.
  2. volver fseek() al principio de la entrada.
  3. Por cada grupo de 19 identificaciones:
    1. Abrir un archivo para cada ID.
    2. Ejecutar a través del archivo de entrada, añadiendo registros coincidentes en el fichero de salida correspondiente.
    3. Cerrar este grupo de archivos 19 de salida.
    4. fseek() al comienzo de la entrada.

Este método no funciona tan bien con múltiples hilos, porque con el tiempo los hilos van a leer totalmente diferentes partes del archivo. Cuando eso sucede, es difícil que el caché de archivos para ser eficiente. Se podría utilizar barreras para mantener los hilos más o menos en el bloqueo de paso.

"Operaciones con archivos Menor número de" Estrategia

Se puede usar múltiples hilos y un gran grupo de búfer para hacer sólo una carrera a través de la entrada. Esto se logra a costa de más de archivos se abre y cierra (probablemente). Cada hilo sería, hasta que todo el archivo se solucionó:

  1. Selecciona la página siguiente sin leer de la entrada.
  2. Ordenar que la entrada en tampones de 2 páginas, una memoria intermedia para cada archivo de salida. Cada vez que una página buffer está lleno:
    1. Marcar la página como no disponible.
    2. Si esta página tiene el valor más bajo página de venta libre, añadirlo al archivo usando fwrite(). Si no es así, espera hasta que sea la más baja (es de esperar, esto no sucede mucho).
    3. Marcar la página como disponibles, y darle el siguiente número de la página.

Se puede cambiar la unidad de lavado de archivos de salida en el disco. Tal vez usted tiene suficiente memoria RAM para recoger 200 páginas a la vez, por archivo de salida?

Cosas que tener cuidado con:

  • ¿Es el alineamiento de página de datos? Si no es así, tendrá que ser inteligentes acerca de la lectura "de la página siguiente".
  • Asegúrese de que usted no tiene dos hilos fwrite()'ing en el mismo archivo de salida al mismo tiempo. Si esto sucede, es posible que un corrupto de las páginas.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top