4 votes

Les chaînes de caractères de ruby sont-elles mises en cache ?

J'ai le code de ce formulaire :

class String
  def is_jpg?
    start_with? "\xFF\xD8\xFF".b
  end
end

String#b renvoie une copie d'une chaîne de caractères mais codée en ASCII-8BIT. Ma question

L'interpréteur ruby est-il assez intelligent pour mettre en cache le résultat de b() dans l'exemple ci-dessus de sorte que les appels à cette méthode pour différentes instances de String n'aient pas à créer une nouvelle copie de " \xFF\xD8\xFF "à chaque fois ? Ou dois-je faire quelque chose comme :

class String
  JPG_SIGNATURE = "\xFF\xD8\xFF".b
  def is_jpg?
    start_with? JPG_SIGNATURE
  end
end

La réponse dépend-elle de la version de ruby et/ou de l'interpréteur ? J'utilise MRI 2.2.x, bientôt 2.3.x.

3voto

kcdragon Points 1457

Non, par défaut, Ruby créera une nouvelle copie du fichier String mais vous pouvez éviter cela en gelant le String

class String
  def is_jpg?
    start_with? "\xFF\xD8\xFF".freeze.b
  end
end

o

class String
  JPG_SIGNATURE = "\xFF\xD8\xFF".freeze.b
  def is_jpg?
    start_with? JPG_SIGNATURE
  end
end

Vous pouvez en savoir plus à ce sujet dans cet article. http://blog.honeybadger.io/when-to-use-freeze-and-frozen-in-ruby/

1voto

kiddorails Points 4799

Pour répondre à votre question :

L'interprète ruby est-il assez intelligent pour mettre en cache le résultat de b()

Non. C'est contraire aux concepts fondamentaux de Ruby. Une chaîne littérale comme celle-ci sera traitée comme un nouvel objet à chaque fois.

def foo
  x = 'foo'
  puts x.object_id
end

> foo
70281000268840
> foo
70281000264340

Votre deuxième solution est la meilleure façon de procéder. La constante doit être définie une fois. Et elle occupera un seul espace en mémoire.

Vous pouvez également définir la même chose avec String::JPG_SIGNATURE = "\xFF\xD8\xFF".b

Modifier : Lire le La réponse de kcdragon . Il a suggéré freeze pour le manipuler et les numéros de référence pour les mêmes sont vraiment jolis !

0voto

Max Points 5042

J'ai évalué trois implémentations : normale sans optimisation, utilisant une const, et utilisant une chaîne gelée.

            user     system      total        real
normal  0.270000   0.000000   0.270000 (  0.272052)
const   0.160000   0.000000   0.160000 (  0.155427)
freeze  0.240000   0.000000   0.240000 (  0.238170)

Il semble que sur ma machine utilisant la machine virtuelle officielle de Ruby, la chaîne n'est pas mise en cache, car l'utilisation d'une constante permet d'améliorer la vitesse. Le fait de geler la chaîne de caractères donne également un gain de vitesse, mais un gain nettement plus faible.

Notez que j'ai dû appeler la méthode millions plusieurs fois afin de voir une différence appréciable. Je classerais cela comme une optimisation prématurée, à moins que votre profilage n'ait montré que cette méthode spécifique est un goulot d'étranglement sérieux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X