¿Por qué Java lee un archivo grande más rápido que C++?
Tengo un archivo de 2 GB (iputfile.txt
) en el que cada línea en el archivo es una palabra, al igual que:
apple
red
beautiful
smell
spark
input
Necesito escribir un programa para leer cada palabra en el archivo e imprimir el recuento de palabras. Lo escribí usando Java y C++, pero el resultado es sorprendente: Java se ejecuta 2,3 veces más rápido que C++. Mi código es el siguiente:
C++:
int main() {
struct timespec ts, te;
double cost;
clock_gettime(CLOCK_REALTIME, &ts);
ifstream fin("inputfile.txt");
string word;
int count = 0;
while(fin >> word) {
count++;
}
cout << count << endl;
clock_gettime(CLOCK_REALTIME, &te);
cost = te.tv_sec - ts.tv_sec + (double)(te.tv_nsec-ts.tv_nsec)/NANO;
printf("Run time: %-15.10f s\n", cost);
return 0;
}
Salida:
5e+08
Run time: 69.311 s
Java:
public static void main(String[] args) throws Exception {
long startTime = System.currentTimeMillis();
FileReader reader = new FileReader("inputfile.txt");
BufferedReader br = new BufferedReader(reader);
String str = null;
int count = 0;
while((str = br.readLine()) != null) {
count++;
}
System.out.println(count);
long endTime = System.currentTimeMillis();
System.out.println("Run time : " + (endTime - startTime)/1000 + "s");
}
Salida:
5.0E8
Run time: 29 s
¿Por qué Java es más rápido que C++ en esta situación, y cómo mejorar la rendimiento de C++?
5 answers
No estás comparando lo mismo. El programa Java lee líneas, dependiendo de la nueva línea, mientras que el programa C++ lee "palabras" delimitadas por espacios en blanco, lo cual es un poco más de trabajo.
Intenta istream::getline
.
Más Tarde
También puede intentar hacer una operación de lectura elemental para leer una matriz de bytes y buscar nuevas líneas.
Incluso después
En mi viejo portátil Linux, jdk1. 7. 0_21 y don't-tell-me-it's-old 4.3.3 toman aproximadamente el mismo tiempo, comparando con C++ getline. (Hemos establecido que leer palabras es más lento.) No hay mucha diferencia entre-O0 y-O2, lo que no me sorprende, dada la simplicidad del código en el bucle.
Última nota Como sugerí, Fin.read (buffer, LEN) con LEN = 1MB y el uso de memchr para buscar '\n' resulta en otra mejora de la velocidad de alrededor del 20%, lo que hace que C (ya no queda C++) sea más rápido que Java.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-09 17:10:21
Hay una serie de diferencias significativas en la forma en que los lenguajes manejan E / S , todo lo cual puede hacer una diferencia, de una manera u otro.
Tal vez la primera (y más importante) pregunta es: ¿cómo es la datos codificados en el archivo de texto. Si se trata de caracteres de un solo byte (ISO 8859-1 o UTF-8), entonces Java tiene que convertirlo en UTF-16 antes de procesar; dependiendo de la configuración regional, C++ puede (o no) también convertir o hacer algunos adicionales comprobación.
Como se ha señalado (parcialmente, al menos), en C++, >>
utiliza
un local específico isspace
, getline
simplemente comparar para
'\n'
, que es probablemente más rápido. (Implementaciones típicas de
isspace
utilizará un mapa de bits, lo que significa una memoria adicional
acceso para cada personaje.)
Los niveles de optimización y las implementaciones de bibliotecas específicas pueden también varían. No es inusual en C++ para una biblioteca la implementación debe ser 2 o 3 veces más rápida que otra.
Finalmente, un diferencia más significativa: C++ distingue
entre archivos de texto y archivos binarios. Has abierto el archivo en
modo texto; esto significa que será "preprocesado" en el
nivel más bajo, incluso antes de que los operadores de extracción lo vean. Este
depende de la plataforma: para las plataformas Unix, el " preprocesamiento"
es un no-op; en Windows, convertirá los pares CRLF en '\n'
,
lo que tendrá un impacto definitivo en el rendimiento. Si recuerdo
correctamente (no he usado Java durante algunos años), Java espera
nivel superior funciones para manejar esto, por lo que funciones como
readLine
será un poco más complicado. Sólo adivinando.
aquí, pero sospecho que la lógica adicional en el más alto
nivel cuesta menos en tiempo de ejecución que el preprocesamiento de búfer en el
nivel inferior. (Si está probando bajo Windows, es posible que
experimente con la apertura del archivo en modo binario en C++. Este
no debe hacer ninguna diferencia en el comportamiento del programa cuando
utilice >>
; cualquier CR adicional se considerará espacio en blanco. Con
getline
, tendrás que añadir lógica para eliminar cualquier final
'\r'
a su código.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-09 17:05:32
Sospecharía que la principal diferencia es que java.io.BufferedReader
funciona mejor que std::ifstream
porque almacena en búfer, mientras que el ifsteam no lo hace. El BufferedReader lee grandes trozos del archivo por adelantado y los entrega a su programa desde la RAM cuando llama readLine()
, mientras que el std::ifstream solo lee unos pocos bytes a la vez cuando se le pide que llame al operador >>
.
El acceso secuencial de grandes cantidades de datos desde el disco duro suele ser mucho más rápido que el acceso a muchos pequeños trozos uno a la vez.
Una comparación más justa sería comparar std:: ifstream con el java.io.FileReader sin búfer.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-09 08:45:16
No soy experto en C++, pero tiene al menos lo siguiente para afectar el rendimiento:
- Almacenamiento en caché a nivel del sistema operativo para el archivo
- Para Java está utilizando un lector de búfer y el tamaño predeterminado del búfer es una página o algo así. No estoy seguro de cómo C++ streams hace esto.
- Dado que el archivo es tan grande que JIT probablemente sería pateado, y probablemente compila el código de bytes de Java mejor que si no activa ninguna optimización para su compilador de C++.
Desde I/O el costo es el costo principal aquí, supongo que 1 y 2 son las razones principales.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-09 17:03:00
También intentaría usar mmap en lugar de lectura/escritura de archivos estándar. Esto debería permitir que su sistema operativo maneje la lectura y escritura mientras que su aplicación solo se ocupa de los datos.
No hay ninguna situación en la que C++ no pueda ser más rápido que Java, pero a veces requiere mucho trabajo de personas muy talentosas. Pero no creo que este deba ser demasiado difícil de superar, ya que es una tarea sencilla.
Mmap para Windows se describe en Mapeo de archivos ( MSDN ).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-09 17:10:27