2009-09-03 15 views
21

que estaba leyendo este libro - Javascript profesional para desarrolladores web, donde el autor menciona la concatenación de cadenas es una operación costosa en comparación con el uso de una matriz para almacenar cadenas y luego utilizando el método de unión para crear la cadena final . Curioso, hice una prueba par aquí para ver cuánto tiempo se ahorraría y esto es lo que tengo -concatenación de cadenas vs memorias intermedias de cadena en Javascript

http://jsbin.com/ivako

De alguna manera, el Firefox por lo general produce tiempos algo similares a ambos lados, pero en IE, cuerda la concatenación es mucho más rápida. Entonces, ¿esta idea ahora puede considerarse obsoleta? (Los navegadores probablemente han mejorado desde?

+0

Acabo de probar su ejemplo en IE 7 (jsbin.com/ivako) y parece ser lo contrario de lo que dice. Obtengo: Concatenación con más: 92829 milisegundos Concatenación con StringBuffer: 125 milisegundos. En Firefox 3.5 en la misma máquina obtengo Concatenación con más: 110 milisegundos Concatenación con StringBuffer: 113 milisegundos –

+0

Esto es peculiar. Pensé que estaba obteniendo resultados sesgados ya que estaba ejecutando el script localmente, así que me puse jsbin. Siempre lo mismo. Estoy usando IE8 y Firefox 3.5. Voy a probar esto en mi IE7 en la pc virtual. – Dhana

+0

92829 milisegundos? Eso es 1 minuto 32 segundos. ¿Estás seguro? – bucabay

Respuesta

26

** EDITAR: supongo que las personas siguen viendo esta publicación, pero ha sido 3+ años, por lo que es mejor para usted simplemente ver: http://jsperf.com/string-concatenation/14

Vea los cambios de esta publicación para ver lo que solía decir.

+0

Muy buena respuesta, pero si las cadenas que se concatenan son más largas (al menos 500 caracteres) la diferencia será evidente sin importar qué tipo de computadora lo ejecute – Rodrigo

+1

** TraceMonkey **, no Trackmonkey:) – kangax

+0

Errores de ortografía :) –

4

Incluso si fuera cierto y la unión() fuera más rápida que la concatenación, no importaría. Estamos hablando de pequeñas cantidades de milisegundos que son completamente insignificantes.

siempre preferiría bien estructurado y fácil de leer código a través de aumento de rendimiento microscópica y creo que el uso de la concatenación se ve mejor y es más fácil de leer.

Sólo mis dos centavos.

+5

Un milisegundo dentro de un ciclo que ocurre muchas veces no siempre es insignificante. Puede agregar hasta segundos, días o años, depende de la aplicación, y no puedo creer que no lo sepas. Tus dos centavos no valen nada. – DaveWalley

+0

En completo acuerdo con @DaveWalley ... si no piensa en considerar la [complejidad] (https://en.wikipedia.org/wiki/Big_O_notation), es decir, el tiempo/espacio de ejecución de su algoritmo, podría significar la diferencia entre una respuesta suave y una lenta. Yo diría que sus dos centavos valen realmente dos centavos ... de deudas. –

+1

Creo que Richard Knop tiene un punto válido total. La legibilidad cuenta mucho en las primeras fases de un proyecto. Siempre que no esté en un bucle i> 1000, no hay nada de malo en la concatenación. Por favor, no caiga en la trampa de la 'Optimización Prematura' ... es un antipatrón muy conocido y causa más dolor en mi experiencia. –

1

En realidad tengo un poco de experiencia en esta área, ya que mi producto primario es un gran IE sólo webapp, que hace un montón de concatenación de cadenas con el fin de construir documentos XML para enviar al servidor. Por ejemplo, en el peor de los casos una página podría tener 5-10 marcos flotantes, cada una con unos pocos cientos de cuadros de texto que cada uno tiene 5-10 expando propiedades.

Para algo así como nuestra función de guardar, iteramos a través de cada pestaña (iframe) y cada entidad en esa pestaña, sacamos todas las propiedades de expansión de cada entidad y las rellenamos todas en un documento XML gigante.

Al perfilar y mejorar nuestro método de guardar, se encontró que el uso de concatention cadena en IE7 fue mucho más lento que el uso de la matriz de cadenas método. Algunos otros puntos de interés fueron que el acceso a las propiedades DOM objeto expando es muy lento, por lo que todos ellos ponen en javascript arrays lugar. Por último, la generación de las matrices de JavaScript sí es en realidad el mejor hecho en el servidor, a continuación, se escribe a continuación, en la página como un control literal que se exectued cuando se carga la página.

+0

Tuve un problema similar en una de mis aplicaciones y hoy decidí probar este enfoque. Por supuesto, las mejoras en IE7 definitivamente eran visibles. – Dhana

2

En mi sistema (IE 8 en Windows 7) los tiempos de StringBuilder en esa prueba rondan entre un 70-100%, es decir, no es estable, aunque el promedio es aproximadamente el 95% del anexar normal.

Si bien es muy fácil ahora sólo para decir "optimización prematura" (y sospecho que en casi todos los casos lo es) hay cosas vale la pena considerar:

asignaciones de memoria

El problema con la concatenación de cadenas repetidas viene repetida y datos repetidos copias (avanzado de cadenas tipos de datos pueden reducir/eliminar gran parte de esto, pero vamos a mantener asumiendo un modelo simplista por ahora). De esto permite plantear algunas preguntas:

  • ¿Qué asignación de memoria se utiliza? En el caso ingenuo, cada str + = x requiere str.length + x.length nueva memoria para ser asignada. El estándar C malloc, por ejemplo, es un asignador de memoria bastante pobre. Las implementaciones de JS han sufrido cambios a lo largo de los años, que incluyen, entre otras cosas, mejores subsistemas de memoria.Por supuesto, estos cambios no se detienen allí y tocan realmente todos los aspectos del código JS moderno. Debido a que ahora antiguas implementaciones pueden haber sido increíblemente lentas en ciertas tareas no implica necesariamente que los mismos problemas todavía existan, o en la misma medida.

  • Como en el ejemplo anterior, la implementación de Array.join es muy importante. Si NO asigna previamente la memoria para la cadena final antes de compilarla, solo ahorra en costos de copia de datos. ¿Cuántos GB/s es la memoria principal en estos días? 10,000 x 50 apenas está presionando un límite. Se esperaría que una operación inteligente Array.join con un POOR MEMORY ALLOCATOR funcione un poco mejor porque se reduce la cantidad de reasignaciones. Se espera que esta diferencia se minimice a medida que el costo de asignación disminuye.

  • El código de micro-punto de referencia puede ser defectuoso dependiendo de si el motor JS crea un nuevo objeto por cada literal de cadena ÚNICA o no. (Esto lo sesgaría hacia el método Array.join, pero debe tenerse en cuenta en general).

  • El punto de referencia es de hecho un micro punto de referencia :) Aumentar el tamaño de crecimiento debe tener un impacto de rendimiento basado en cualquiera o todas (y algunas) condiciones anteriores. En general, es fácil mostrar casos extremos que favorecen algún método u otro; el caso de uso esperado suele ser de mayor importancia.

Aunque, sinceramente, para cualquier forma de cuerdo edificio cuerda, me acaba de utilizar la concatenación de cadenas normales hasta el momento en que se determinó que era un cuello de botella, si alguna vez.

Volvería a leer el enunciado anterior del libro y ver si hay quizás otras consideraciones implícitas que el autor realmente quería invocar, como "para cadenas muy grandes" o "cantidades locas de operaciones de cadena" o "en JScript/IE6 ", etc ... Si no, entonces tal afirmación es tan útil como" Insertar ordenamiento es O (n * n) "[los costos realizados dependen del estado de los datos y el tamaño de n por supuesto] .

Y la exención de responsabilidad: la velocidad del código depende del navegador, el sistema operativo, el hardware subyacente, las fuerzas gravitacionales de la luna y, por supuesto, cómo se siente su computadora acerca de usted.

-1

bien, en relación con esto aquí es un módulo relacionado:

http://www.openjsan.org/doc/s/sh/shogo4405/String/Buffer/0.0.1/lib/String/Buffer.html

Este es un medio eficaz para la creación de memorias intermedias de Cuerda, mediante el uso de

var buffer = new String.Buffer(); 
buffer.append("foo", "bar"); 

Este es el tipo más rápido de puesta en práctica de Buffers de cadena que conozco. Primero que nada, si está implementando String Buffers, no use push porque es un método incorporado y lento, por un empujón itera sobre toda la matriz de argumentos, en lugar de simplemente agregar un elemento.

Todo depende de la implementación del método de unión, algunas implementaciones del método de unión son realmente lentas y algunas son relativamente grandes.

+0

¿Tiene un enlace a algo que sugiera que el método push es lento? – Prestaul

+0

http: // openjsan.org/doc/j/JH/jhuni/StandardLibrary/1,81/lib/Array.html usted tiene que tratar con __proto__, así como la longitud de la matriz de argumentos, hay dos cosas que no debería ser necesario. http://groups.google.com/group/jquery-dev/browse_thread/thread/5019fa537c8d3595 – jhuni

2

En principio, el libro es correcto. Unirse a una matriz debe ser mucho más rápido que la concatenación repetida a la misma cadena. Como un algoritmo simple en cadenas inmutables, es demostrablemente más rápido.

El truco es: autores de JavaScript, siendo en gran parte dabblers no expertos, han escrito una carga de código que hay en la naturaleza que utiliza la concatenación, y relativamente poco ‘bueno’ código que utilizan métodos como la matriz de unirse. El resultado es que los autores de los navegadores pueden obtener una mejor mejora en la velocidad en una página web promedio al buscar y optimizar la opción 'mala' más común de concatenación.

Así que eso es lo que sucedió. Las versiones de navegador más nuevas tienen algunas cosas de optimización bastante peludas que detectan cuando estás haciendo una carga de concatenaciones, y las piratea para que internamente funcione más como una matriz de unión, a más o menos la misma velocidad.

0

Como sabemos, no todos los navegadores se crean iguales. Debido a esto, se garantiza que el rendimiento en diferentes áreas difiera de un navegador a otro.

Dejando eso de lado, noté los mismos resultados que tú; sin embargo, después de eliminar la clase de búfer innecesaria, y simplemente usar una matriz directamente y una cadena de 10000 caracteres, los resultados fueron aún más ajustados/consistentes (en FF 3.0.12): http://jsbin.com/ehalu/

A menos que esté haciendo una gran cantidad de concatenación de cadenas, diría que este tipo de optimización es una micro-optimización. Su tiempo podría utilizarse mejor limitando DOM reflows y queries (generalmente el uso de document.getElementbyById/getElementByTagName), implementando el almacenamiento en caché de los resultados de AJAX (donde corresponda), y explotando el evento burbujeante (hay un enlace en alguna parte, simplemente no puedo encontrarlo ahora) .

+0

Probé la secuencia de comandos, por desgracia, sigue el tiempo de espera de mí en Firefox 3.5. – Dhana

+0

Incluso más de un punto culminante de las diferencias en el rendimiento entre los navegadores y sus versiones. –

Cuestiones relacionadas