2010-01-26 14 views
5

Quiero plantear una pregunta aparentemente simple que no puedo encontrar la respuesta en ninguna parte. ¿Existe un FAST algoritmo moderno para la entrada y/o salida de archivos que se puede compilar con todos los compiladores estándar compatibles con C++ y funciona para todos los sistemas operativos sin la necesidad de bibliotecas externas?Algoritmo rápido de plataforma cruzada para leer/escribir archivo en C++

  1. he encontrado que la manera más rápida es utilizar archivos de memoria asignada, pero eso no lo haré porque nosotros queremos la misma pieza de código que funciona en todas las plataformas
  2. no podemos utilizar las API de Win32 API como causa que hará que la plataforma es específica
  3. no quiero utilizar c, quiero que el algoritmo sea sólo puro código C++ con STL, si es posible, no un feo C con asm entremezclada truco/truco
  4. marcos o externo las bibliotecas que no pertenecen a standart C++ no deben usarse como wxWidgets, Qt, MFC, etc.
  5. The big empasis de toda esta cuestión es que el algoritmo es el RÁPIDO como sea posible, algo a lo largo de las líneas de la velocidad de hacerlo con los archivos de memoria asignada, incluso más rápido sería grande, pero sé que no es posible

¿Alguna vez has visto algo tan loco investigado por alguien más excepto yo? ¿Es posible tal algoritmo?

Gracias por las recomendaciones

Respuesta

9

con las siguientes restricciones:

pueden ser compilados con todos los compiladores de C++ estándar compatibles y obras para todos los sistemas operativos sin necesidad de bibliotecas externas?

Se ha limitado prácticamente a las funciones IO del archivo de biblioteca estándar. Posiblemente funciones POSIX (dependiendo del subconjunto de "todos los compiladores estándar C++ compatibles" que esté considerando).

Si no son lo suficientemente rápidos para usted, tendrá que empezar a soltar algunas restricciones.

+1

De acuerdo. La única E/S de archivo estándar de C++ es la de la biblioteca estándar, es decir. archivo de encabezado '' o ''. Si desea una E/S de archivo rápida, lo más importante sería ** no ** leer/escribir archivos de un byte a la vez, sino leer/escribir fragmentos grandes de una sola vez. – stakx

+0

¿se puede leer todo el archivo de una sola vez con iostream? ¿Ofrecería eso una ventaja de rendimiento, que no creo? no es un encabezado cstdio a c? – user258883

+2

Leer todo el archivo a la vez es aún más lento que asignarlo a la memoria. –

9

Esto no tiene nada que ver con un "algoritmo".

Cuando se trata de escribir datos en un archivo, está a merced del sistema operativo: los archivos mapeados en memoria son "rápidos" porque solo está escribiendo en la memoria y el sistema operativo lo vuelve a sincronizar su propio tiempo. Si el sistema operativo no lo admite, no tiene suerte en ese sentido, a menos que desee implementar su propia capa de asignación de memoria.

Por cierto, POSIX tiene mmap, por lo que si se limita a los sistemas que cumplen con POSIX, está bien.

2

Algunos puntos:

  • Esto no tiene nada que ver con algoritmos.
  • Querer apuntar TODOS los sistemas operativos no es un objetivo muy productivo (y es imposible
  • su código no funciona en una plataforma en particular hasta que lo haya probado). En cambio, me centraría en algunos sistemas operativos que son factibles, como POSIX + Win32.
  • En ese caso, puede hacer una asignación de memoria, por ejemplo, implementando mmap() para Windows (encima de MapViewOfFile() etc. - el código fuente de git tiene una implementación de mmap para Windows si necesita inspiración)
  • Si no puede usar la asignación de memoria, recomendaría usar la api de archivo C normal en lugar de las secuencias de archivos de C++ si el rendimiento es un gran problema. Aunque las transmisiones de C++ tienen el potencial de un mayor rendimiento para algunas operaciones, en la práctica es bastante más lento.
  • Pero, para obtener un buen rendimiento, a menudo puede ser "lo suficientemente bueno" solo para asegurarse de que está tratando sus datos de una manera sensata. Lea los datos secuencialmente, no vuelva a leer, etc. Perfecto es el enemigo del bien;)
+0

@kusma: Me gustaría ver comparaciones de rendimiento entre las funcionalidades 'stdio' de C y' iostream' de C++. ¿Puede, por casualidad, señalarme esos recursos? porque una vez miré el código fuente de la biblioteca C++ 'iostream' (más específicamente, la implementación que viene con MinGW) y tuve la impresión de que en realidad es solo un envoltorio muy delgado (basado en plantillas) alrededor de la E/S del archivo C funciones. Por lo tanto, no esperaría ver ninguna diferencia significativa en el rendimiento. – stakx

+0

¿El enemigo de dios? Yikes ... :) –

+0

stakx: Desafortunadamente, no. Los resultados se perdieron hace mucho tiempo. Hice algunos perfiles en MSVC alrededor de 2001, después de que un amigo informara de desaceleraciones significativas en GCC/Linux al usar std :: istream (en comparación con las API de C). IIRC, ambos encontramos que la caída en el rendimiento fue aproximadamente la misma, alrededor del 30%. Sin embargo, podría ser que la memoria no me sirve para las cifras. Drew: Lo siento, quise decir "el enemigo de satanás", por supuesto;) – kusma

0

Los otros carteles son correctos en cuanto a que el rendimiento siempre está en desacuerdo con la genericidad (multiplataforma).

Sin embargo, en general, obtendrá los mejores resultados "almacenando en búfer" su entrada, utilizando fread() para leer en trozos relativamente grandes de datos y procesarlos.

Sé que es una respuesta bastante básica y general, pero eso es lo más específico que puede obtener sin ser más específico de la plataforma, o saber más sobre la entrada específica que está procesando.

1

La lectura secuencial en bloques que son múltiplos (o potencias de 2) del tamaño del bloque del sistema de archivos puede ayudar. Luego separa tus datos una vez que el bloque está en la memoria. Hay un libro blanco en algún lugar donde probaron el rendimiento para varios tamaños de bloques. Ojalá pudiera encontrarlo de nuevo.

También podría intentar tener un hilo dedicado para leer bloques del archivo, y otro que haga las manipulaciones de datos en la memoria (con las sincronizaciones adecuadas, por supuesto). Esto le permite usar la CPU para procesar datos mientras bloquea sus llamadas de lectura de archivos.

De todos modos, si le das una oportunidad a estas ideas, avísanos si notas una diferencia. Los resultados reales de sus pruebas de referencia serían interesantes.

+0

La mayoría de los discos duros usan tamaños de bloques que son un múltiplo de 512 bytes. Con los discos duros más grandes, puede ser 1024 o más grande. –

+0

Los tamaños de búfer utilizados por las capas superiores e inferiores pueden ser diferentes a los del sistema de archivos. Experimenta con diferentes poderes de 2 (no te limites a 512/1024, sube hasta, digamos, 256kiB). Recuerdo que 4kiB era un número mágico utilizado en una de esas capas en Linux, pero no recuerdo dónde. Lo siento, no puedo ser más específico. –

+0

4k es el tamaño predeterminado de un bloque de sistema de archivos. –

1

Fast IO se reduce generalmente a dos cosas:

  1. Minimizar los datos de la copia de
  2. Minimizar contexto del núcleo/cambio de usuario

La mayoría de todas las técnicas de IO intentan abordar uno o el otro. El código multiplataforma más rápido para IO que conozco es el sistema Perl IO. Sugeriría echar un vistazo a the source. Los hackers de Perl han pasado décadas recibiendo su IO lo más rápido posible en tantas plataformas como sea posible.

4

Para poner otra perspectiva sobre "misericordia del sistema operativo", la mayoría de los gastos generales en la copia de archivos recae en el sistema operativo. Un archivo fragmentado tomará más tiempo para leer que un archivo desfragmentado. No hay funciones C++ genéricas o estándar para detectar archivos fragmentados.

El método más rápido en C++:

std::ifstream in_file; 
std::ofstream out_file; 

out_file << in_file.rdbuf(); 

se pueden encontrar más detalles mediante la búsqueda en la web con las palabras clave "copia de archivos rdbuf". El fragmento anterior deja la copia hasta el sistema operativo, pero es portátil en todas las plataformas. Al leer las secuencias de E/S de C++, puede establecer el tamaño del búfer de lectura o hacer que use su propio búfer.

La copia de archivos más rápida requiere una funcionalidad específica de la plataforma, como transferencias DMA. Usar subprocesos y múltiples búferes, podría acelerar esto; pero C++ no tiene soporte para hilos (hay un estándar de facto, POSIX, que admite subprocesos). Un hilo leerá en los búferes mientras otro hilo escribe desde los búferes.

Cuestiones relacionadas