java - objetos - ¿Por qué el rendimiento de ArrayList es diferente si se lo menciona como Lista?
recorrer arraylist java foreach (2)
Entonces, mi primera pregunta es ¿por qué Java VM debería interpretar esto como una lista secuencial en el primer método?
La JVM no tiene ningún concepto de listas de acceso secuencial o aleatorio. (Aparte de la interfaz de marcador) Es el desarrollador de la implementación que reconoce que ArrayList realiza búsquedas de acceso aleatorio en O (1) tiempo en lugar de O (n) tiempo.
¿Depende de la arquitectura o la cantidad de núcleos de procesador?
No, verá una diferencia entre el -client
por ejemplo, Windows de 32 bits y el servidor, por ejemplo, cualquier JVM de 64 bits.
Sospecho que ejecutó la prueba List en segundo lugar. Es probable que esto sea más rápido ya que el código está más advertido tanto en el JIT como en el caché de la CPU. Le sugiero que realice cada prueba al menos tres veces, ejecute primero las pruebas más largas e ignore la primera ejecución que realice.
Nota: contains () es O (n) para una Lista, por lo que sus tiempos crecen O (n ^ 2) Obviamente, usted no usaría una Lista si quisiera ignorar los duplicados y observando el comportamiento de un código realmente ineficiente. confuso ya que es muy susceptible a las sutilezas de lo que se optimiza y lo que no. Obtendrá resultados mucho más significativos al comparar el código que ya es razonablemente óptimo.
Se mencionó en el artículo de kjellkod que si pasamos ArrayList
en el método que recibe List
como argumento, entonces perdemos en rendimiento porque ArrayList implementa una interfaz RandomAccess adicional. Ejemplo del artículo:
// SLOWER: as shown in http://ideone.com/1wnF1
private static void linearInsertion(Integer[] intArray, List<Integer> list) {
[...]
int list_size = list.size();
for (int i = 0; i < list_size; i++) {
if (integer.compareTo(list.get(i)) >= 0) { // ... more code
// FASTER: as shown in http://ideone.com/JOJ05
private static void linearInsertion(Integer[] intArray, ArrayList<Integer> list) {
[...]
int list_size = list.size();
for (int i = 0; i < list_size; i++) {
if (integer.compareTo(list.get(i)) >= 0) { // ... more code
De referencia:
Se recomienda que los algoritmos de listas genéricas comprueben si la lista dada es una instancia de esta interfaz antes de aplicar un algoritmo que proporcionaría un rendimiento deficiente si se aplicara a una lista de acceso secuencial, y modificar su comportamiento si fuera necesario para garantizar un rendimiento aceptable.
Sin embargo, si realmente aprobamos ArrayList en los métodos anteriores y la list instanceof RandomAccess
verificación de list instanceof RandomAccess
, será verdadero en ambos casos. Entonces, mi primera pregunta es ¿por qué Java VM debería interpretar esto como una lista secuencial en el primer método?
He modificado las pruebas del artículo para verificar este comportamiento en mi máquina. Cuando la prueba se ejecuta en el ideone , muestra resultados similares a los de kjellkod. Pero cuando lo ejecuté localmente, obtuve resultados inesperados, que son contrarios a la explicación del artículo así como también a mi comprensión. Parece que en mi caso ArrayList como iteración de lista es 5-25% más rápido que hacer referencia a él como una ArrayList:
¿Cómo se puede explicar esta diferencia? ¿Depende de la arquitectura o la cantidad de núcleos de procesador? La configuración de mi máquina en funcionamiento es Windows 7 Professional x64, Intel Core i5-3470 (4 núcleos, 4 hilos), 16 GB de RAM.
Aunque el código es el mismo en ambos métodos aún teóricamente puede haber una diferencia porque a nivel de JVM invocar un método de interfaz es diferente de invocar un método de clase. Son 2 operaciones diferentes de bytecode: invokeinterface
e invokevirtual
. Ver http://bobah.net/d4d/source-code/misc/invokevirtual-vs-invokeinterface-performance-benchmark