A veces, Java supera a C ++ en los puntos de referencia. Por supuesto, a veces C ++ supera.
Ver los siguientes enlaces:
- http://keithlea.com/javabench/
- http://blog.dhananjaynene.com/2008/07/performance-comparison-c-java-python-ruby-jython-jruby-groovy/
- http://blog.cfelde.com/2010/06/c-vs-java-performance/
Pero, ¿cómo es esto posible? Me sorprende que el bytecode interpretado pueda ser más rápido que un lenguaje compilado.
¿Alguien puede explicar? ¡Gracias!
java
c++
performance
Deets McGeets
fuente
fuente
Respuestas:
Primero, la mayoría de las JVM incluyen un compilador, por lo que "bytecode interpretado" es bastante raro (al menos en el código de referencia, no es tan raro en la vida real, donde el código suele ser más que unos pocos bucles triviales que se repiten con mucha frecuencia )
En segundo lugar, un buen número de los puntos de referencia involucrados parecen estar bastante sesgados (ya sea por intención o incompetencia, realmente no puedo decir). Solo por ejemplo, hace años, miré algunos de los códigos fuente vinculados desde uno de los enlaces que publicaste. Tenía un código como este:
Como
calloc
proporciona memoria que ya está puesta a cero, usar elfor
bucle para ponerlo a cero nuevamente es obviamente inútil. Esto fue seguido (si la memoria sirve) llenando la memoria con otros datos de todos modos (y sin depender de que se ponga a cero), por lo que toda la puesta a cero fue completamente innecesaria de todos modos. Reemplazar el código anterior con un simplemalloc
(como cualquier persona sensata hubiera usado para comenzar) mejoró la velocidad de la versión de C ++ lo suficiente como para vencer a la versión de Java (por un margen bastante amplio, si la memoria sirve).Considere (para otro ejemplo) el
methcall
punto de referencia utilizado en la entrada del blog en su último enlace. A pesar del nombre (y de cómo podrían verse las cosas), la versión C ++ de esto no mide mucho sobre la sobrecarga de llamadas al método. La parte del código que resulta ser crítica está en la clase Toggle:La parte crítica resulta ser la
state = !state;
. Considere lo que sucede cuando cambiamos el código para codificar el estado como un enint
lugar de unbool
:Este cambio menor mejora la velocidad general en aproximadamente un margen de 5: 1 . Aunque el punto de referencia estaba destinado a medir el tiempo de llamada al método, en realidad, la mayor parte de lo que medía era el tiempo de conversión entre
int
ybool
. Ciertamente estoy de acuerdo en que la ineficiencia mostrada por el original es desafortunada, pero dado que rara vez parece surgir en el código real, y la facilidad con la que se puede solucionar cuando / si surge, me cuesta pensar de ello como mucho significado.En caso de que alguien decida volver a ejecutar los puntos de referencia involucrados, también debo agregar que hay una modificación casi igualmente trivial a la versión de Java que produce (o al menos una vez producido; no he vuelto a ejecutar las pruebas con un JVM reciente para confirmar que todavía lo hacen) una mejora bastante sustancial en la versión de Java también. La versión de Java tiene un NthToggle :: enable () que se ve así:
Cambiar esto para llamar a la función base en lugar de manipular
this.state
directamente proporciona una mejora de velocidad bastante sustancial (aunque no lo suficiente como para mantenerse al día con la versión modificada de C ++).Entonces, lo que terminamos es una suposición falsa sobre los códigos de bytes interpretados frente a algunos de los peores puntos de referencia que he visto. Tampoco está dando un resultado significativo.
Mi propia experiencia es que con programadores igualmente experimentados que prestan igual atención a la optimización, C ++ vencerá a Java más a menudo que no, pero (al menos entre estos dos), el lenguaje rara vez hará tanta diferencia como los programadores y el diseño. Los puntos de referencia que se citan nos dicen más sobre la (in) competencia / (des) honestidad de sus autores que sobre los idiomas que pretenden comparar.
[Editar: como está implícito en un lugar anterior, pero nunca lo dije tan directamente como probablemente debería haberlo hecho, los resultados que estoy citando son los que obtuve cuando probé esto ~ hace 5 años, usando implementaciones de C ++ y Java que eran actuales en ese momento . No he vuelto a ejecutar las pruebas con las implementaciones actuales. Una mirada, sin embargo, indica que el código no se ha solucionado, por lo que todo lo que habría cambiado sería la capacidad del compilador para ocultar los problemas en el código.]
Sin embargo, si ignoramos los ejemplos de Java, en realidad es posible que el código interpretado se ejecute más rápido que el código compilado (aunque difícil y algo inusual).
La forma habitual en que esto sucede es que el código que se interpreta es mucho más compacto que el código de la máquina, o se ejecuta en una CPU que tiene un caché de datos más grande que el caché de código.
En tal caso, un pequeño intérprete (p. Ej., El intérprete interno de una implementación de Forth) puede encajar completamente en el caché de código, y el programa que está interpretando se ajusta completamente en el caché de datos. El caché suele ser más rápido que la memoria principal en un factor de al menos 10, y a menudo mucho más (un factor de 100 ya no es particularmente raro).
Entonces, si el caché es más rápido que la memoria principal por un factor de N, y se requieren menos de N instrucciones de código de máquina para implementar cada código de bytes, el código de bytes debería ganar (estoy simplificando, pero creo que la idea general aún debería ser aparente).
fuente
C / C ++ hecho a mano por un experto con tiempo ilimitado será al menos tan rápido o más rápido que Java. En última instancia, Java está escrito en C / C ++, por lo que, por supuesto, puede hacer todo lo que Java hace si está dispuesto a realizar un esfuerzo de ingeniería suficiente.
Sin embargo, en la práctica, Java a menudo se ejecuta muy rápido por las siguientes razones:
Al mismo tiempo, C / C ++ también tiene algunas ventajas:
En general:
fuente
El tiempo de ejecución de Java no interpreta bytecode. Más bien, usa lo que se llama Just In Time Compilation . Básicamente, a medida que se ejecuta el programa, toma bytecode y lo convierte en código nativo optimizado para la CPU en particular.
fuente
En igualdad de condiciones, se podría decir: no, Java nunca debería ser más rápido . Siempre puede implementar Java en C ++ desde cero y, por lo tanto, obtener al menos el mismo rendimiento. En la práctica, sin embargo:
Como comentario aparte, esto me recuerda el debate sobre C en los años 80/90. Todos se preguntaban "¿puede C ser tan rápido como el ensamblaje?". Básicamente, la respuesta fue: no en papel, pero en realidad el compilador de C creó un código más eficiente que el 90% de los programadores de ensamblaje (bueno, una vez que maduró un poco).
fuente
http://www.ibm.com/developerworks/java/library/j-jtp09275/index.html
fuente
Si bien un programa Java completamente optimizado rara vez superará a un programa C ++ completamente optimizado, las diferencias en cosas como la administración de memoria pueden hacer que muchos algoritmos se implementen idiomáticamente en Java más rápido que los mismos algoritmos implementados idiomáticamente en C ++.
Como señaló @Jerry Coffin, hay muchos casos en que los cambios simples pueden hacer que el código sea mucho más rápido, pero a menudo puede tomar demasiados ajustes impuros en un idioma u otro para que la mejora del rendimiento valga la pena. Eso es probablemente lo que verías en un buen punto de referencia que muestra que Java funciona mejor que C ++.
Además, aunque generalmente no es tan significativo, hay algunas optimizaciones de rendimiento que un lenguaje JIT como Java puede hacer que C ++ no puede. El tiempo de ejecución de Java puede incluir mejoras después de compilar el código, lo que significa que el JIT puede producir código optimizado para aprovechar las nuevas (o al menos diferentes) características de la CPU. Por esta razón, un binario Java de 10 años podría superar a un binario C ++ de 10 años.
Por último, la seguridad de tipo completo en la imagen más grande puede, en casos muy raros, ofrecer mejoras de rendimiento extremas. Singularity , un sistema operativo experimental escrito casi por completo en un lenguaje basado en C #, tiene una comunicación entre procesos y multitarea mucho más rápida debido al hecho de que no hay necesidad de límites de proceso de hardware o costosos cambios de contexto.
fuente
Publicado por Tim Holloway en JavaRanch:
Fuente: http://www.coderanch.com/t/547458/Performance/java/Ahead-Time-vs-Just-time
fuente
Esto se debe a que el paso final que genera el código de la máquina ocurre de manera transparente dentro de la JVM cuando se ejecuta su programa Java, en lugar de ser explícito al construir su programa C ++.
Debe tener en cuenta el hecho de que las JVM modernas pasan mucho tiempo compilando el código de bytes sobre la marcha al código de máquina nativo para hacerlo lo más rápido posible. Esto permite que la JVM realice todo tipo de trucos de compilación que pueden ser aún mejores al conocer los datos de creación de perfiles del programa que se está ejecutando.
Algo así como alinear automáticamente a un getter, de modo que no sea necesario un JUMP-RETURN para obtener un valor, acelera las cosas.
Sin embargo, lo que realmente ha permitido programas rápidos es una mejor limpieza posterior. El mecanismo de recolección de basura en Java es más rápido que el manual sin malloc en C. Muchas implementaciones modernas sin malloc usan un recolector de basura debajo.
fuente
Respuesta corta: no lo es. Olvídalo, el tema es tan antiguo como el fuego o la rueda. Java o .NET no es y no será más rápido que C / C ++. Es lo suficientemente rápido para la mayoría de las tareas en las que no necesita pensar en la optimización en absoluto. Al igual que los formularios y el procesamiento SQL, pero ahí es donde termina.
Para los puntos de referencia, o pequeñas aplicaciones escritas por desarrolladores incompetentes, sí, el resultado final será que Java / .NET probablemente estará cerca y tal vez incluso más rápido.
En realidad, cosas simples como asignar memoria en la pila o simplemente usar memzones simplemente matarán Java / .NET en el acto.
El mundo recolectado de basura está utilizando una especie de memzone con toda la contabilidad. Agregue memzone a C y C será más rápido allí mismo en el acto. Especialmente para esos puntos de referencia de Java "C" código de alto rendimiento ", que van así:
Intente usar variables basadas en pila en C / C ++ (o ubicación nueva), se traducen en
sub esp, 0xff
, es una sola instrucción x86, supere eso con Java, no puede ...La mayoría de las veces veo esos bancos en los que se compara Java contra C ++, lo que me hace pensar, ¿con qué? Estrategias de asignación de memoria incorrectas, contenedores de crecimiento propio sin reservas, múltiples novedades. Esto ni siquiera se acerca al código C / C ++ orientado al rendimiento.
También una buena lectura: https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf
fuente
La realidad es que ambos son simplemente ensambladores de alto nivel que hacen exactamente lo que el programador les dice, exactamente cómo el programador les dice que lo hagan en el orden exacto que el programador les dice. Las diferencias de rendimiento son tan pequeñas que no son importantes para todos los fines prácticos.
El lenguaje no es "lento", el programador escribió un programa lento. Muy raramente, un programa escrito de la mejor manera en un idioma supera a un programa que hace lo mismo usando la mejor manera del idioma alternativo, a menos que el autor del estudio esté dispuesto a moler su hacha particular.
Obviamente, si va a un caso marginal raro como los sistemas embebidos en tiempo real, la elección del idioma puede marcar la diferencia, pero ¿con qué frecuencia es este el caso? y de esos casos, con qué frecuencia la elección correcta no es obvia a ciegas.
fuente
Keith Lea te dice que hay "defectos obvios", pero no hace nada con respecto a esos "defectos obvios". En 2005, esas viejas tareas fueron descartadas y reemplazadas por las tareas que ahora se muestran en el juego de puntos de referencia .
Keith Lea le dice que "tomó el código de referencia para C ++ y Java del desactualizado Great Computer Language Shootout y ejecutó las pruebas", pero en realidad solo muestra medidas para 14 de 25 de esas pruebas desactualizadas .
Keith Lea ahora te dice que no estaba tratando de probar nada con la publicación del blog siete años antes, pero en ese entonces dijo "Estaba harto de escuchar a la gente decir que Java era lento, cuando sé que es bastante rápido ...", lo que sugiere en aquel entonces había algo que intentaba probar.
Christian Felde te dice: "No creé el código, solo volví a ejecutar las pruebas". como si eso lo absolviera de cualquier responsabilidad por su decisión de publicitar mediciones de las tareas y programas que Keith Lea seleccionó.
¿Las mediciones de incluso 25 pequeños programas proporcionan evidencia definitiva?
Esas medidas son para programas ejecutados como Java "modo mixto" Java no interpretado - "Recuerda cómo funciona HotSpot". Puede averiguar fácilmente qué tan bien Java ejecuta el "bytecode interpretado", porque puede obligar a Java a interpretar solo el bytecode, simplemente cronometrando que algunos programas Java se ejecuten con y sin la opción -Xint.
fuente
Me divierte lo generalizada que es esta extraña noción de "bytecode interpretado". ¿Alguna vez han oído hablar de la compilación JIT? Su argumento no se puede aplicar a Java.
Pero, dejando a un lado JVM, hay casos en los que un código de subproceso directo o incluso una interpretación trivial de bytecode puede superar fácilmente a un código nativo altamente optimizado. La explicación es bastante simple: el código de bytes puede ser bastante compacto y se ajustará a su pequeño caché cuando una versión de código nativo del mismo algoritmo termine teniendo varios errores de caché para una sola iteración.
fuente
Dejando a un lado JIT, GC, etc., C ++ puede ser muy, muy fácilmente, mucho más lento que Java. Esto no aparecerá en los puntos de referencia, pero la misma aplicación escrita por el desarrollador de Java y un desarrollador de C ++ puede ser mucho más rápida en Java.
En cuanto a los patrones de herencia avanzados, estos son bastante similares: C ++ tiene algunos que Java no tiene y viceversa, pero todos ellos introducen una sobrecarga similar y significativa. Por lo tanto, no hay una ventaja especial de C ++ en la programación de objetos pesados.
Una advertencia más: GC puede ser más rápido o más lento que administrar asignaciones manualmente. Si asigna muchos objetos pequeños, en el entorno GC generalmente se asigna una porción de memoria y se envían partes de ella según sea necesario para nuevos objetos. En administrado: cada objeto = asignación separada lleva un tiempo considerable. OTOH, si mallocas () mucha memoria a la vez y luego solo asignas partes de ella a tus objetos manualmente, o usas pocas instancias más grandes de objetos, puedes llegar mucho más rápido.
fuente
obj.fetchFromDatabase("key")
tres veces dentro de cinco líneas de código para la misma clave, pensará dos veces si buscar ese valor una vez y almacenarlo en una variable local. Si escribeobj->"key"
con->
una sobrecarga para actuar como recuperación de la base de datos, es mucho más propenso a dejarlo pasar porque el costo de la operación no es aparente.De alguna manera, Stack Exchange no toma mis otros puntos de pila, así que desafortunadamente no hay respuesta ...
Sin embargo, la segunda respuesta más votada aquí está llena de información errónea en mi humilde opinión.
Una aplicación enrollada a mano por un experto en C / C ++ SIEMPRE va a ser mucho más rápida que una aplicación Java, punto. No hay "tan rápido como Java o más rápido". es más rápido, precisamente por los elementos que cita a continuación:
Compilación JIT : ¿Realmente espera que un optimizador automático tenga la inteligencia de un programador experto y vea el vínculo entre la intención y el código que la CPU realmente ejecutará? Además, todo el JIT que haces es tiempo perdido en comparación con un programa ya compilado.
Garbage Collection es una herramienta que simplemente desasigna recursos que un programador habría olvidado desasignar, de una manera más o menos eficiente.
Evidentemente, esto solo puede ser más lento de lo que un programador experto en C (elegiste el término) haría para manejar su memoria (y no, no hay fugas en las aplicaciones escritas correctamente).
Una aplicación C de rendimiento optimizado conoce la CPU en la que se está ejecutando, ha sido compilada en ella, de lo contrario, eso significa que usted no dio todos los pasos para el rendimiento, ¿verdad?
Estadísticas de tiempo de ejecución Esto está más allá de mi conocimiento, pero sospecho que un experto en C tiene más que suficiente conocimiento de predicción de sucursales para volver a ser más astuto que la optimización automatizada.
Muy buenas bibliotecas Hay muchas funciones no muy optimizadas fácilmente disponibles a través de bibliotecas en Java, y lo mismo es cierto en cualquier lenguaje, sin embargo, las bibliotecas más optimizadas están escritas en C, especialmente para el cálculo.
La JVM es una capa de abstracción, lo que implica cosas buenas, muchas de las cuales están arriba, y también implica que la solución general es más lenta por diseño.
En general:
Java nunca puede alcanzar la velocidad de C / C ++ debido a la forma en que funciona en una JVM con mucha protección, características y herramientas.
C ++ tiene una clara ventaja clara en software optimizado, ya sea para computación o juegos, y es común ver que las implementaciones de C ++ ganen concursos de codificación hasta el punto de que las mejores implementaciones de Java solo se pueden ver en la segunda página.
En la práctica, C ++ no es un juguete y no le permitirá escapar de muchos errores que la mayoría de los lenguajes modernos pueden manejar, sin embargo, al ser más simple y menos seguro, es inherentemente más rápido.
Y como conclusión, me gustaría decir que la mayoría de las personas no dan dos centavos por esto, que al final la optimización es un deporte reservado solo a unos pocos desarrolladores afortunados y que, excepto en los casos en que el rendimiento realmente es una preocupación (es decir, multiplicar el hardware por 10 no lo ayudará, o representará al menos unos pocos millones), la mayoría de los gerentes preferirán una aplicación no optimizada y una tonelada de hardware.
fuente
new
omalloc()
. En general, puede ser mucho más rápido que cualquier administración manual de memoria, ya que no podría reubicar objetos manualmente. Entonces, todo su razonamiento es claramente erróneo y parcial. Su conocimiento de los algoritmos GC y los métodos de optimización JIT es demasiado limitado.He visto al menos dos mmo impresionantes hechos en Java, decir que no es lo suficientemente rápido para los juegos es un nombre inapropiado. El hecho de que los diseñadores de juegos prefieran C ++ más que otros lenguajes dice que no solo está relacionado con Java, solo significa que los programadores nunca han incursionado en ningún otro lenguaje / paradigma de programación. Cualquier cosa en cualquier lenguaje tan avanzado como C / C ++ o incluso Java puede producir código que técnicamente podría cumplir o vencer el argumento de la velocidad. Todo eso bien dicho se reduce a lo que los programadores saben, con qué equipos trabajan más y lo más importante por qué usan dichas herramientas. Dado que estamos abordando el aspecto de desarrollo de juegos de la programación, entonces debe haber más en el argumento. En pocas palabras ' Todo se trata de dinero y tiempo para un negocio empeñado en usar herramientas que cumplan con el control de calidad y en el mundo real no tiene peso en las razones xx para elegir C ++ en lugar de Java o cualquier otro lenguaje. Es solo una decisión de producción en masa. En el nivel más básico de algoritmos informáticos, todos con los que estamos jugando son unos y ceros, el argumento de la velocidad es uno de los argumentos más tontos jamás aplicados a los juegos. Si desea aumentar la velocidad de esa manera, elimine los lenguajes de programación por completo y trabaje con el ensamblaje que posiblemente sea la mejor ventaja con diferencia.
fuente