2009-03-17 13 views
5

Cada texto que he leído sobre los símbolos de Ruby habla de la eficacia de los símbolos sobre las cadenas. Pero, esto no es la década de 1970. Mi computadora puede manejar un poco de recolección de basura extra. ¿Me equivoco? Tengo el último y más grande procesador dual core Pentium y 4 gigas de RAM. Creo que eso debería ser suficiente para manejar algunas cuerdas.Las computadoras modernas no son lo suficientemente potentes como para manejar cadenas sin la necesidad de utilizar símbolos (en Ruby)

Respuesta

17

El ordenador también puede ser capaz de manejar "un poco de recolección de basura extra", pero ¿qué pasa cuando ese "poco" tiene lugar en un bucle interno que corre millones de veces? ¿Qué ocurre cuando se ejecuta en un sistema integrado con memoria limitada?

Hay muchos lugares en los que puede escaparse usando cadenas de cualquier manera, pero en algunos no puede. Todo depende del contexto.

+0

Sí, es cierto: un bucle de larga duración definitivamente podría consumir recursos. No pensé en crear cadenas dentro de un bucle pero, claro, supongo que podrías hacer eso. Gracias por el consejo. –

2

Es bueno que los símbolos se garanticen de manera única, que pueden tener algunos buenos efectos que no obtendría de String (como creo que sus direcciones son exactamente iguales).

Además, tienen un significado diferente y es posible que desee utilizarlos en diferentes áreas, pero Ruby no es demasiado estricto con ese tipo de cosas de todos modos, por lo que puedo entender su pregunta.

13

Es cierto, no necesita tokens tan mal por razones de memoria. Su computadora podría, sin duda, manejar todo tipo de manejo de cadenas retorcidas.

Pero, además de ser más rápido, los tokens tienen la ventaja adicional (especialmente con el color del contexto) de gritar visualmente: MÍRAME, YO SOY LA LLAVE DE UN PAR DE VALOR CLAVE. Esa es una buena razón para usarlos para mí.

También hay otras razones ... y la ganancia de rendimiento en muchas de ellas podría ser más de lo que cree, especialmente haciendo algo parecido a la comparación.

Al comparar dos símbolos ruby, el intérprete simplemente compara dos direcciones de objeto. Al comparar dos cadenas, el intérprete tiene que comparar cada carácter de a uno por vez. Ese tipo de computación puede sumar si haces mucho de esto.

Los símbolos tienen sus propios problemas de rendimiento ... nunca se recogen basura.

Vale la pena leer este artículo: http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-ruby-symbol

+0

Interesante. No pensé en el hecho de que los símbolos no son basura. Artículo genial Gracias por el enlace. Es como, "Todo lo que siempre quisiste saber sobre símbolos" :) Paz, amigo. –

+0

El colorante de contexto también es un buen punto. –

1

Un carácter menos para escribir. Esa es toda la justificación que necesito para utilizarlos en cadenas para claves hash, etc.

+2

+1; Cuando leí esto por primera vez, me dije: "¡Vaya, qué razón más superficial!". Pero cuanto más pensaba en ello, más me daba cuenta de cuán grande era esta motivación para mi propio uso de símbolos. Gracias por ayudarme a darme cuenta de mí mismo. –

1

Aquí está la verdadera razón de la diferencia: las cadenas nunca son lo mismo. Cada instancia de una cadena es un objeto separado, incluso si el contenido es idéntico. Y la mayoría de las operaciones en cadenas crearán nuevos objetos de cadena. Considere lo siguiente:

a = 'zowie' 
b = 'zowie' 
a == b   #=> true 

En la superficie, que sería fácil afirmar que a y b son los mismos. La mayoría de las operaciones de sentido común funcionarán como es de esperar. Pero:

a.object_id #=> 2152589920 (when I ran this in irb) 
b.object_id #=> 2152572980 
a.equal?(b) #=> false 

Ellos miran la misma, pero son diferentes objetos. Ruby tuvo que asignar memoria dos veces, realizar el método String#initialize dos veces, etc. Están ocupando dos lugares separados en la memoria. Y oye!Se hace aún más divertido cuando intenta modificarlos:

a += ''  #=> 'zowie' 
a.object_id #=> 2151845240 

Aquí añadimos nada a a y dejar el contenido es exactamente el mismo - pero Ruby no lo saben. Todavía asigna un objeto String completamente nuevo, reasigna la variable a y el antiguo objeto String se queda esperando la eventual recolección de elementos no utilizados. Ah, y la cadena vacía '' también obtiene un objeto String temporal asignado solo por la duración de esa línea de código. Pruébalo y mira:

''.object_id #=> 2152710260 
''.object_id #=> 2152694840 
''.object_id #=> 2152681980 

¿Estas asignaciones de objetos son rápidas en tu procesador slick multi-Gigahertz? Claro que lo son ¿Masticarán gran parte de tus 4 GB de RAM? No, no lo harán. Pero hágalo unos millones de veces, y comienza a sumarse. La mayoría de las aplicaciones utilizan cadenas temporales por todas partes, y su código probablemente esté lleno de literales de cadenas dentro de sus métodos y bucles. Cada uno de esos literales de cadena y tal asignará un nuevo objeto String, cada vez que se ejecute esa línea de código. El problema real ni siquiera es la pérdida de memoria; es el tiempo perdido cuando la recolección de basura se activa con demasiada frecuencia y su aplicación comienza a colgarse.

Por el contrario, echar un vistazo a los símbolos:

a = :zowie 
b = :zowie 
a.object_id #=> 456488 
b.object_id #=> 456488 
a == b   #=> true 
a.equal?(b) #=> true 

Una vez que el símbolo :zowie se hizo, que nunca va a hacer otro. Cada vez que te refieres a un símbolo dado, te estás refiriendo al mismo objeto. No hay tiempo ni memoria desperdiciada en nuevas asignaciones. Esto también puede ser un inconveniente si te vuelves loco con ellos - son nunca basura recolectada, por lo que si comienzas a crear innumerables símbolos dinámicamente a partir de la entrada del usuario, estás arriesgando una fuga de memoria interminable. Pero para literales simples en tu código, como valores constantes o claves hash, son casi perfectos.

¿Eso ayuda? No se trata de lo que tu aplicación hace una vez. Se trata de lo que hace millones de veces.

Cuestiones relacionadas