Seria o OrderedHash menos eficiente que o Hash?
Contextualizando: Algumas vezes queremos que um dicionário (ou tabela de símbolos) tenha não apenas uma relação de chave e objeto como também uma ordem (a palavra dicionário aliás remete bem a ideia de chaves ordenadas, cada qual com uma definição relacionada). O ActiveSupport do Rails oferece uma classe chamada OrderedHash para honrar a especificação do YAML que exige a implementação de um mapa ordenado (omap). Quais os riscos de usar o ActiveSupport::OrderedHash em outros contextos?
Para responder a questão vou utilizar de dois recursos. Um simples teste de performance e o código-fonte do OrderedHash.
require 'benchmark' require 'active_support' TIMES= 100000 a = [] Benchmark.bm do |bm| bm.report("Hash") do TIMES.times { |i| a = {} a[:a] = 1 a[:b] = 2 } end bm.report("Ordered Hash") do TIMES.times { |i| a = ActiveSupport::OrderedHash.new a[:a] = 1 a[:b] = 2 } end end
Resultado:
user system total real Hash 1.430000 0.070000 1.500000 ( 1.655311) Ordered Hash 1.770000 0.130000 1.900000 ( 2.235623)
Duas perguntas... Por que? e Qual impacto disso?
Por que?
A desvantagem do Ordered Hash frente ao Hash é linear. Por maior que seja a coleção de objetos, o tempo de execução do ordered hash é proporcional ao tempo do próprio hash. Porém a diferença não era para ser tão grande. O Ordered Hash deveria ter uma lista com a ordem das chaves (o impacto deveria ser mínimo).Isso não ocorre devido a implementação da funções hash nativas do Ruby. Nas palavras do rails:
In MRI the Hash class is core and written in C. In particular, methods are programmed with explicit C function calls and polymorphism is not honored.
For example, []= is crucial in this implementation to maintain the @keys array but hash.c invokes rb_hash_aset() originally. This prevents method reuse through inheritance and forces us to reimplement stuff.
For instance, we cannot use the inherited #merge! because albeit the algorithm itself would work, our []= is not being called at all by the C code.
Então o ActiveSupport reimplementa algumas funções que não seriam necessárias em outras ocasições.
Comentários