sobre secuencial ordenar manejo indexados indexado directo datos codigo binarios archivos archivo acceso c++ performance file-io

ordenar - ¿Cuál es el método más rápido para la E/S de archivos secuenciales de alto rendimiento en C++?



ordenar datos de un archivo en c (7)

Suponiendo lo siguiente para ...
Salida:
El archivo se abre ...
Los datos se ''transmiten'' al disco. Los datos en la memoria se encuentran en un gran buffer contiguo. Se escribe en el disco en su forma original directamente desde ese búfer. El tamaño del búfer es configurable, pero se fija durante la duración del flujo. Los búferes se escriben en el archivo, uno tras otro. No se realizan operaciones de búsqueda.
... el archivo está cerrado.

Entrada:
Un archivo grande (escrito de forma secuencial como se indica anteriormente) se lee del disco de principio a fin.

¿Existen pautas generalmente aceptadas para lograr la E / S de archivo secuencial más rápida posible en C ++?

Algunas posibles consideraciones:

  • Pautas para elegir el tamaño de búfer óptimo
  • ¿Será una biblioteca portátil como boost :: asio demasiado abstraída para exponer las complejidades de una plataforma específica, o se puede suponer que es óptima?
  • ¿La E / S asincrónica siempre es preferible a la sincrónica? ¿Qué ocurre si la aplicación no está unida a CPU?

Me doy cuenta de que esto tendrá consideraciones específicas de la plataforma. Agradezco las pautas generales, así como las de plataformas específicas.
(mi interés más inmediato en Win x64, pero también me interesan los comentarios sobre Solaris y Linux)


¿Existen pautas generalmente aceptadas para lograr la E / S de archivo secuencial más rápida posible en C ++?

Regla 0: medida Use todas las herramientas de generación de perfiles disponibles y familiarícelas. Es casi un mandamiento en la programación que si no lo midió no sabe qué tan rápido es, y para E / S esto es aún más cierto. Asegúrese de probar bajo las condiciones reales de trabajo si es posible. Un proceso que no tiene competencia para el sistema de E / S puede ser optimizado en exceso, ajustado para condiciones que no existen bajo cargas reales.

  1. Usa memoria mapeada en lugar de escribir en archivos. Esto no siempre es más rápido, pero permite la oportunidad de optimizar la E / S de una manera específica para el sistema operativo pero relativamente portátil, evitando la copia innecesaria y aprovechando el conocimiento del sistema operativo sobre cómo se está utilizando el disco. ("Portátil" si usa un contenedor, no una llamada API específica del sistema operativo).

  2. Intenta linealizar tu producción tanto como sea posible. Tener que saltar por la memoria para encontrar los búferes para escribir puede tener efectos notables en condiciones optimizadas, ya que las líneas de caché, la paginación y otros problemas del subsistema de memoria comenzarán a importar. Si tiene muchos buffers, busque soporte para scatter-gather I / O que intente hacer esa linealización por usted.

Algunas posibles consideraciones:

  • Pautas para elegir el tamaño de búfer óptimo

Tamaño de página para principiantes, pero prepárate para sintonizar desde allí.

  • ¿Será una biblioteca portátil como boost :: asio demasiado abstraída para exponer las complejidades de una plataforma específica, o se puede suponer que es óptima?

No asuma que es óptimo. Depende de cuán exhaustivamente se ejercite la biblioteca en su plataforma, y ​​de cuánto esfuerzo pongan los desarrolladores en hacerlo rápido. Habiendo dicho que una biblioteca de E / S portátil puede ser muy rápida, porque existen abstracciones rápidas en la mayoría de los sistemas, y generalmente es posible encontrar una API general que cubra muchas de las bases. Boost.Asio es, según mi leal saber y entender, bastante ajustado para la plataforma en la que se encuentra: hay toda una familia de API específicas de variante de sistema operativo y SO para la E / S asíncrona rápida (por ejemplo, epoll , /dev/epoll , kqueue , Windows superpuesto E / S ), y Asio los envuelve a todos.

  • ¿La E / S asincrónica siempre es preferible a la sincrónica? ¿Qué ocurre si la aplicación no está unida a CPU?

La E / S asíncrona no es más rápida en un sentido crudo que la E / S síncrona. Lo que hace la E / S asíncrona es asegurarse de que su código no esté perdiendo tiempo esperando que se complete la E / S. Es más rápido de una manera general que el otro método de no perder ese tiempo, es decir, usar hilos, porque volverá a llamar a su código cuando la E / S esté lista y no antes. No hay inicios en falso o preocupaciones con subprocesos inactivos que necesitan ser finalizados.


Como señaló anteriormente, todo depende de la máquina / sistema / bibliotecas que esté utilizando. Una solución rápida en un sistema puede ser lenta en otro.

Sin embargo, una guía general sería escribir en la mayor cantidad de fragmentos posible.
Por lo general, escribir un byte a la vez es el más lento.

La mejor manera de saberlo con certeza es codificar algunas formas diferentes y perfilarlas.


En Linux, las lecturas y escrituras almacenadas aceleran mucho las cosas, cada vez más al aumentar los tamaños de los buffers, pero los rendimientos están disminuyendo y generalmente quiere usar BUFSIZ (definido por stdio.h ) ya que los tamaños de búfer más grandes no ayudarán mucho.

mmap ing proporciona el acceso más rápido a los archivos, pero la llamada mmap sí es bastante costosa. Para archivos pequeños (16 Kb), las llamadas al sistema de read y write ganan (consulte https://.com/a/39196499/1084774 para obtener los números de lectura en lectura y mmap ).


Obtendrá el rendimiento más rápido absoluto utilizando CreateFile y ReadFile . Abra el archivo con FILE_FLAG_SEQUENTIAL_SCAN .

Lea con un tamaño de búfer que es una potencia de dos. Solo el benchmarking puede determinar este número. Lo he visto 8K una vez. ¡Otra vez descubrí que era 8 millones! Esto varía salvajemente

Depende del tamaño de la memoria caché de la CPU, de la eficacia de la lectura anticipada del sistema operativo y de la sobrecarga asociada a la realización de muchas escrituras pequeñas.

El mapeo de memoria no es la manera más rápida. Tiene más sobrecarga porque no puede controlar el tamaño del bloque y el sistema operativo necesita fallas en todas las páginas.


Para Windows, querrá asegurarse de usar el FILE_FLAG_SEQUENTIAL_SCAN en su llamada a CreateFile (), si opta por utilizar la API de Windows específica de la plataforma. Esto optimizará el almacenamiento en caché para la E / S. En lo que respecta al tamaño del búfer, normalmente se recomienda un tamaño de búfer que sea un múltiplo del tamaño del sector del disco. 8K es un buen punto de partida con poco que ganar al ir más grande.

Este artículo analiza la comparación entre sincronización y sincronización en Windows.

http://msdn.microsoft.com/en-us/library/aa365683(VS.85).aspx


Preguntaste sobre C ++, pero parece que ya pasaste de eso y estás listo para ser un poco específico de la plataforma.

En Windows, FILE_FLAG_SEQUENTIAL_SCAN con una asignación de archivos es probablemente la forma más rápida. De hecho, su proceso puede salir antes de que el archivo realmente entre en el disco. Sin una operación de limpieza explícitamente bloqueada, Windows puede tardar hasta 5 minutos en comenzar a escribir esas páginas.

Debe tener cuidado si los archivos no están en dispositivos locales sino en una unidad de red. Los errores de red aparecerán como errores SEH, que deberá estar preparado para manejar.

En * nixes, puede obtener un rendimiento un poco más alto escribiendo secuencialmente en un dispositivo de disco sin formato. Esto también es posible en Windows, pero no tan bien soportado por las API. Esto evitará un poco de sobrecarga del sistema de archivos, pero puede no ser suficiente para ser útil.

En términos generales, la RAM es 1000 o más veces más rápida que los discos, y la CPU es aún más rápida. Probablemente no haya muchas optimizaciones lógicas que ayudarán, excepto evitar los movimientos de las cabezas de disco (buscar) siempre que sea posible. Un disco dedicado solo para este archivo puede ayudar significativamente aquí.


Un consejo general es desactivar el almacenamiento en búfer y leer / escribir en trozos grandes (pero no demasiado grandes), entonces perderá demasiado tiempo esperando a que complete la E / S completa, de lo contrario podría comenzar a masticar en el primer megabyte. Es trivial encontrar el punto óptimo con este algoritmo, solo hay un botón para activar: el tamaño del fragmento).

Más allá de eso, para entrada mmap() ing el archivo compartido y de solo lectura es (si no el más rápido, entonces) la forma más eficiente. Llame a madvise() si su plataforma lo tiene, para decirle al kernel cómo va a atravesar el archivo, de modo que pueda volverse loco y tirar las páginas de nuevo rápidamente.

Para la salida, si ya tiene un búfer, considere respaldarlo con un archivo (también con mmap() ), por lo que no tiene que copiar los datos en el espacio de usuario.

Si mmap() no es de su agrado, entonces está fadvise() y, para los realmente difíciles, la E / S de archivo asíncrono.

(Todo lo anterior es POSIX, los nombres de Windows pueden ser diferentes).