Entiendo que tanto Java como Perl intentan bastante difícil encontrar un tamaño de búfer predeterminado de tamaño único para leer en archivos, pero sus elecciones son cada vez más anticuadas y tengo un problema al cambiar la opción predeterminada cuando viene a Perl.¿Cómo puedo configurar el tamaño del búfer de lectura de archivos en Perl para optimizarlo para archivos grandes?
En el caso de Perl, que creo utiliza 8K almacenamientos intermedios por defecto, similar a la elección de Java, no puedo encontrar una referencia utilizando el motor de búsqueda perldoc (realmente Google) sobre cómo aumentar el buffer de entrada de archivo predeterminado tamaño para decir, 64K.
Desde el enlace de arriba, para mostrar cómo 8K tampones no escalan:
Si las líneas suelen tener alrededor de 60 caracteres cada una, entonces el archivo 10000 línea cuenta con unos 610.000 caracteres en ella. Leer el archivo línea por línea con almacenamiento en búfer solo requiere 75 llamadas al sistema y 75 espera para el disco, en lugar de 10,001.
Así que para un archivo de 50.000.000 línea con 60 caracteres por línea (incluyendo la nueva línea al final), con un buffer de 8 K, que va a hacer 366.211 llamadas al sistema para leer un archivo 2.8GiB. Como comentario adicional, puede confirmar este comportamiento mirando el i/o de lectura delta (en Windows al menos, arriba en * nix muestra lo mismo de alguna manera también estoy seguro) en la lista de procesos del administrador de tareas como su programa Perl toma 10 minutos para leer en un archivo de texto :)
Alguien hizo la pregunta sobre aumentar el tamaño del búfer de entrada Perl en perlmonks, alguien respondió here que podría aumentar el tamaño de "$ /", y así aumentar el tamaño del búfer Sin embargo, desde el perldoc:
Configuración $/a una referencia a un número entero, escalar que contiene un número entero, o escalar que es convertible en un entero intentará leer los registros en lugar de líneas, con el tamaño máximo del registro de ser el referencia d entero.
así que supongo que esto no aumenta realmente el tamaño del búfer que utiliza Perl para leer por delante del disco cuando se utiliza la típica:
while(<>) {
#do something with $_ here
...
}
idioma
"línea por línea".
Ahora podría ser que una versión de "leer un registro a la vez y luego analizarla en líneas" diferente del código anterior sea más rápida en general, y eludir el problema subyacente con el idioma estándar y no poder cambie el tamaño predeterminado del búfer (si eso es realmente imposible), porque podría establecer el "tamaño de registro" en cualquier cosa que desee y luego analizar cada registro en líneas individuales, y esperar que Perl haga lo correcto y termine haciendo un sistema llamada por registro, pero agrega complejidad, y todo lo que quiero hacer es obtener un rendimiento fácil aumentando el almacenamiento intermedio utilizado en el ejemplo anterior a un tamaño razonablemente grande, digamos 64K, o incluso ajustando el tamaño del almacenamiento intermedio al tamaño óptimo para lecturas largas usando una secuencia de comandos de prueba en mi sistema, sin necesidad de complicaciones adicionales.
Las cosas son mucho mejores en Java en lo que respecta al soporte directo para aumentar el tamaño del búfer.
En Java, creo que el tamaño de búfer predeterminado actual que utiliza java.io.BufferedReader también es 8192 bytes, aunque las referencias actualizadas en los documentos JDK son equívocas, por ejemplo, el 1.5 solo dicen:
Se puede especificar el tamaño del búfer o se puede aceptar el tamaño predeterminado. El valor predeterminado es lo suficientemente grande para la mayoría de los propósitos.
suerte con Java que no tiene que confiar en los desarrolladores de JDK de haber tomado la decisión correcta para su aplicación y puede establecer su propio tamaño del búfer (64K en este ejemplo):
import java.io.BufferedReader;
[...]
reader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8"), 65536);
[...]
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
/* do something with the line here */
foo(line);
}
Sólo hay tanto rendimiento que puede exprimir al analizar una línea a la vez, incluso con un gran búfer, y hardware moderno, y estoy seguro de que hay formas de obtener cada onza de rendimiento de la lectura en un archivo leyendo gran cantidad- los registros de línea y dividir cada uno en tokens y luego hacer cosas con esos tokens una vez por registro, pero agregan complejidad y casos extremos (aunque si hay una solución elegante en Java puro (solo con las características presentes en JDK 1.5) que sería genial conocer. Aumentar el tamaño del búfer en Perl resolvería el 80% del problema de rendimiento para Perl al menos, mientras se mantienen las cosas simples.
Mi pregunta es:
¿Hay una manera de ajustar que el tamaño de búfer en Perl para el lenguaje anterior típica "línea por línea", similar forma en que el tamaño del búfer se incrementó en el ejemplo de Java?
Sería bueno publicar un enlace a más información sobre los controladores Perl 5.10. –
Lo único diferente de las versiones anteriores es que los identificadores están bendecidos en el paquete IO :: Handle. Esa es la única diferencia. En particular, simplemente abrir un archivo no significa que pueda invocar ningún método en el manejador. Tienes que "usar IO :: Handle" para que los métodos se definan. –
Eso no es nuevo en 5.10; Filehandles han sido bendecidos en IO :: Handle durante mucho tiempo (o, para compatibilidad con versiones anteriores, en FileHandle si eso estaba cargado). Pero como dice Elliot, los métodos no están definidos a menos que use IO :: Handle. – ysth