2009-06-21 16 views
8

He estado tratando de escribir un código Java muy rápido que tiene que hacer un montón de E/S. Estoy usando un archivo de mapeado de memoria que devuelve un ByteBuffer:Archivos mapeados en memoria en Java

public static ByteBuffer byteBufferForFile(String fname){ 
    FileChannel vectorChannel; 
    ByteBuffer vector; 
    try { 
     vectorChannel = new FileInputStream(fname).getChannel(); 
    } catch (FileNotFoundException e1) { 
     e1.printStackTrace(); 
     return null; 
    } 
    try { 
     vector = vectorChannel.map(MapMode.READ_ONLY,0,vectorChannel.size()); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     return null; 
    } 
    return vector; 
} 

El problema que estoy teniendo es que el método ByteBuffer .array() (que debe volver a [] matriz de bytes) no funciona para archivos de solo lectura. Quiero escribir mi código para que funcione con los búferes de memoria construidos en la memoria y los búferes leídos desde el disco. Pero no quiero ajustar todos mis buffers a una función ByteBuffer.wrap() porque me preocupa que esto disminuya la velocidad. Así que he estado escribiendo dos versiones de todo, una que toma un byte [], la otra que toma un ByteBuffer.

¿Debo simplemente envolver todo? ¿O debería escribir todo dos veces?

+3

punto de referencia y publicar los resultados, incluso si un experto puede indicarle en una dirección que la dirección podría no funcionar para su situación. ¡¡¡¡Punto de referencia!!!! – basszero

Respuesta

10

¿Alguien realmente comprueba si ByteBuffers creado por soporte de mapeo de memoria invocando .array() en primer lugar, independientemente de readonly/readwrite?

De mi hurgando, por lo que puedo decir, la respuesta es NO. La capacidad de ByteBuffer de devolver una matriz directa byte[] a través de ByteBuffer.array() está garantizada por la presencia de ByteBuffer.hb (byte[]), que siempre se establece en nulo cuando se crea MappedByteBuffer.

Lo que me apena un poco, porque esperaba hacer algo similar a lo que el autor de la pregunta quería hacer.

+0

Estoy de acuerdo. Apesta. No puedo creer que ByteBuffer no implemente array(). Por otro lado, hicimos algunas pruebas de rendimiento, y descubrimos que a veces es más rápido usar .get() con un archivo mapeado en memoria que usar programa-io, y a veces es más rápido usar programa-io. Es muy raro. Pero hay más variaciones en los archivos programados que en los mapas asignados en memoria. – vy32

+3

Un 'byte []' tiene que estar en el montón. Un bloque de memoria mapeado de memoria tiene que estar fuera del montón. Sería bueno si la distinción fuera transparente, pero prefiero utilizar el método getLong/putLong de un ByteBuffer de todos modos (estos son mucho más rápidos con el uso de ordenamiento nativo) –

1

El uso de la funcionalidad ByteBuffer.wrap() no impone una gran carga. Asigna un objeto simple e inicializa algunos enteros. Por lo tanto, escribir su algoritmo contra ByteBuffer es su mejor opción si necesita trabajar con archivos de solo lectura.

4

Wrapping byte [] no ralentizará las cosas ... no habrá grandes copias de matriz u otros pequeños problemas de rendimiento. Desde JavaDocs: java.nio.ByteBuffer .wrap()

Encapsula una matriz de bytes en un búfer.

El nuevo búfer estará respaldado por la matriz de bytes dada; es decir, modificaciones en el búfer causará que la matriz se modifique y vice versa. La capacidad del nuevo buffer y el límite serán array.length, su posición será cero, y su marca no estará definida. Su matriz de respaldo será la matriz dada, y su desplazamiento de la matriz será cero.

+0

Gracias. Solo me preocupa tener que leer cada byte con .get (i) en lugar de [i], ya que .get (i) implica una llamada al método, mientras que [i] se realiza en el bytecode. – vy32

+4

Parece una inquietud de rendimiento terriblemente "fina", y huele como una optimización prematura para mí. La JVM es buena sobre cosas como esta. Compare esto para demostrarlo a usted mismo de una manera u otra. –

+0

En realidad, estoy haciendo análisis forense de computadora, procesando terabytes de información. En mi experiencia hasta la fecha, la JVM no ha optimizado tanto como esperaba. – vy32

5

Siempre es bueno no reinventar las ruedas. Apache ha proporcionado una hermosa biblioteca para realizar operaciones de E/S. Eche un vistazo a http://commons.apache.org/io/description.html

Este es el escenario al que sirve. Supongamos que tiene algunos datos que prefiere mantener en la memoria, pero no sabe de antemano cuántos datos habrá. Si hay demasiado, desea escribirlo en el disco en lugar de acaparar la memoria, pero no desea escribir en el disco hasta que lo necesite, porque el disco es lento y es un recurso que necesita seguimiento para la limpieza .

Por lo tanto, crea un búfer temporal y comienza a escribirlo. Si/cuando alcanza el umbral de lo que desea conservar en la memoria, necesitará crear un archivo, escribir lo que hay en el búfer de ese archivo y escribir todos los datos posteriores en lugar del búfer .

Eso es lo DeferredOutputStream para con vosotros. Oculta todo el messing alrededor en el punto de cambio. Todo lo que necesita hacer es crear la secuencia diferida en primer lugar, configurar el umbral y luego solo escribir a su gusto.

EDIT: Acabo de hacer una pequeña re-búsqueda a través de Google y encontré este enlace: http://lists.apple.com/archives/java-dev/2004/Apr/msg00086.html (archivos a gran velocidad relámpago lectura/escritura). Muy impresionante.

+0

Corrija si estoy equivocado. Está buscando una forma rápida de realizar operaciones de E/S. ¿¿Correcto?? –

+0

En realidad, solo busco maneras rápidas de hacer I, pero también estoy buscando maneras de procesar los buffers con la cantidad mínima de copias de buffer. – vy32

+0

@GauravSaini: ¿Refieres 'DeferredOutputStream' de Apache commons-io? No puedo encontrar dicha clase en Javadoc para v2.3 y v2.2. –

Cuestiones relacionadas