Eu fiz o hash de cada palavra duas vezes para contá-la apenas uma vez

Eu fiz o profiling de um parser de logs na semana passada. Ele conta códigos de erro em um log diário. A lógica principal é uma simples atualização de dicionário.

A maioria dos desenvolvedores escreve assim:

if (counts.TryGetValue(code, out int c))
    counts[code] = c + 1;
else
    counts[code] = 1;

Este código faz o hash da chave duas vezes. O TryGetValue encontra a entrada calculando o hash e percorrendo o bucket. Em seguida, o indexador faz exatamente o mesmo trabalho novamente para atualizar o valor. Você desperdiça ciclos de CPU na mesma chave e no mesmo hash duas vezes por token.

Você pode pular a segunda etapa. Use CollectionsMarshal.GetValueRefOrAddDefault.

ref int slot = ref CollectionsMarshal.GetValueRefOrAddDefault(counts, code, out _);
slot++;

Este método encontra ou cria o slot em uma única etapa. Ele fornece uma referência diretamente ao armazenamento. Você realiza um hash e uma busca no bucket. Então, você altera o valor no local (in place).

Eu testei isso com 5 milhões de tokens.

Resultados: • TryGetValue + indexador: 160,0 ms • GetValueRefOrAddDefault: 95,0 ms

A versão de uma única busca é 1,7x mais rápida.

Crucialmente, as alocações de memória permaneceram idênticas. Este truque não economiza memória. Ele apenas economiza CPU. Se o seu código está lento devido à coleta de lixo (garbage collection), esta mudança não fará nada. Se o seu código está lento devido a contagens intensas, isso ajuda.

Use isso quando o seu loop realizar muitas atualizações em chaves existentes. O benefício aumenta conforme a proporção de atualizações em relação às inserções cresce.

Um aviso: A referência aponta para o armazenamento interno do dicionário. Ela só permanece válida até a próxima alteração estrutural. Não mantenha a referência se você adicionar ou remover chaves. Obtenha a ref, altere o valor e siga em frente.

Use TryGetValue para a maioria das tarefas. É mais fácil de ler. Use a versão com ref apenas quando o loop do seu dicionário for um gargalo de desempenho.

Fonte: https://dev.to/ssukhpinder/i-hashed-every-word-twice-to-count-it-once-1mg9