2009-10-10 8 views
7

¿Cuál es una forma eficiente para una aplicación multiproceso de Java donde muchos hilos tienen que leer exactamente el mismo archivo (> 1GB de tamaño) y exponerlo como un flujo de entrada? Me di cuenta de que si hay muchos subprocesos (> 32), el sistema comienza a contender por E/S y tiene muchas esperas de E/S.Java multihebra lectura de un único archivo grande

He considerado cargar el archivo en una matriz de bytes compartida por todos los subprocesos: cada subproceso crearía un ByteArrayInputStream, pero la asignación de una matriz de bytes de 1GB simplemente no funcionará.

También consideré usar un único FileChannel y cada subproceso creando un InputStream sobre él usando Channels.newInputStream(), sin embargo, parece que es el FileChannel el que mantiene el estado del InputStream.

+1

¿Necesita cada subproceso todo el contenido del archivo? ¿O cada uno puede buscar los datos relevantes que necesita? –

+0

Cada hilo necesita leer todo el archivo. – bob

+0

El sistema tiene 8 gb de memoria y no me importaría asignar una matriz de 1 GB. Pero a la JVM simplemente no parece gustarle esto: usa 100% de CPU tratando de asignar la matriz durante mucho tiempo. – bob

Respuesta

10

Me parece que va a tener para cargar el archivo en la memoria si desea evitar la contención de IO. El sistema operativo hará algo de almacenamiento en búfer, pero si te parece que eso no es suficiente, tendrás que hacerlo tú mismo.

¿Realmente necesita 32 hilos? Es de suponer que no tiene casi tantos núcleos, así que use menos hilos y obtendrá menos cambio de contexto, etc.

¿Todos los hilos procesan el archivo de principio a fin? De ser así, ¿podría dividir efectivamente el archivo en fragmentos? Lea el primero (digamos) 10MB de datos en la memoria, deje que todos los hilos lo procesen, luego pase a los siguientes 10MB, etc.

Si eso no le funciona, ¿cuánta memoria tiene en comparación con la tamaño del archivo? Si tiene mucha memoria pero no desea asignar una gran matriz, podría leer todo el archivo en la memoria, pero en muchas matrices de bytes más pequeños. Luego, deberá escribir una secuencia de entrada que abarque todas las matrices de bytes, pero eso debería ser factible.

+0

@jon, ¿sería posible usar las herramientas nio para mapear una estructura Java en el archivo en el disco así que todo lo que se necesita es escribir la estructura java y dejar que la JVM/OS averigüe cómo manejar los detalles reales de lectura ? –

+1

@Thorbjorn: Bueno, Java admite archivos mapeados en memoria, pero si tiene más información de la que tiene el sistema operativo sobre cómo va a usar el archivo, es posible que pueda hacerlo mejor. –

1

algunas ideas:

  1. Escribe una aplicación personalizada InputStream que actúa como una vista de un FileChannel. Escriba esto de manera que no dependa de ningún estado en FileChannel. (es decir: cada instancia debe hacer un seguimiento de su propia posición y leer debe usar lecturas absolutas en el FileChannel subyacente.) Esto al menos lo ayuda a resolver los problemas que tuvo con Channels.newInputStream(), pero puede no resolver sus problemas de contención de IO. .

  2. Escriba una implementación de InputStream personalizada que actúa como una vista en un MappedByteBuffer. El mapeo de memoria no debería ser tan malo como leer todo en la memoria a la vez, pero aún así comerá hasta 1GB de espacio de direcciones virtuales.

  3. Igual que el n. ° 1, pero tienen algún tipo de capa de almacenamiento en caché compartida. No probaría esto a menos que resulte 1 que no sea lo suficientemente eficiente y 2 no sea factible. En realidad, el sistema operativo ya debería estar almacenando en caché para usted en el n. ° 1, por lo que aquí básicamente intenta ser más inteligente que el almacenamiento en caché del sistema de archivos del sistema operativo.

5

puede abrir el archivo varias veces en modo de solo lectura. Puede acceder al archivo de la forma que desee. Simplemente deje el almacenamiento en caché en el sistema operativo. Cuando es demasiado lento, puede considerar algún tipo de almacenamiento en caché basado en fragmentos, donde todos los subprocesos pueden acceder al mismo caché.

0

Eso es un archivo muy grande. ¿Puede obtener el archivo entregado como un conjunto de archivos más pequeño? Solo entregar este archivo será un gran trabajo incluso en una red corporativa.

A veces es más fácil cambiar el proceso que el programa.

Puede que sea mejor escribir algo para dividir el archivo en una cantidad de fragmentos y procesarlos por separado.

Cuestiones relacionadas