9
votes

Mettre à jour efficacement les liaisons dans un dictionnaire .NET

J'utilise un dictionnaire pour accumuler le nombre d'occurrences de clés et, par conséquent, l'opération principale écrit une paire de valeurs de clé lorsque la valeur est la valeur précédente plus une ou une seule valeur précédente. Cependant, cela nécessite deux opérations de dictionnaire distinctes (lire et écrire) lorsque je pouvais simplement faire un ( addorupdate ).

Je remarque que le dictionnaire simultané prend en charge addorupdate mais le dictionnaire ordinaire générique n'apparaît pas.

Par conséquent, un dictionnaire de références à des INT mutables est plus rapide. Cependant, cela introduit des références inutiles, ce qui signifie des allocations de tas et d'écrire des barrières. Donc, je suppose que cela est possible de faire de manière significative meilleure mais je ne peux pas voir comment sans réécriture dictionnaire à partir de zéro. Ai-je raison?


5 commentaires

Vous essayez donc d'éliminer l'une des recherches dans un scénario d'ajout ou de mise à jour?


Un dictionnaire simultané semble assez performant dans de nombreux cas, avez-vous vérifié s'il fournit des performances suffisantes pour votre scénario?


Pouvez-vous trier les valeurs de clé? Je suppose que la plupart seront O (n log n) afin que vous puissiez avoir à tester la meilleure performance


Peut-être que vous pourriez essayer d'utiliser un tableau avec des numérations d'éléments et du dictionnaire de clé / Index-in-TRay - cela nécessitera une recherche dictionnaire et une indexation de tableau - peut être un peu plus rapide dans les cas extrêmes


On dirait que vous avez raison, vous pouvez faire un peu mieux. Une alternative pratique à écrire à partir de zéro commence à partir de la mise en œuvre de la mono: github.com/mono/mono/blob/master/mcs/class/corlib/...


3 Réponses :


2
votes

Une mise à jour du dictionnaire ne nécessite pas de recherches multiples si vous utilisez des types de référence:

Dites que vous avez un dictionnaire dictionnaire code>, où foo code> est Un type de référence et comprend un Nombre Code> Propriété: P>

void UpdateCount(string key)
{
    Foo f;
    if (dict.TryGetValue(key, out f))
    {
        // do the update
        ++f.Count;
    }
    else
    {
        dict[key] = 1;
    }
}


0 commentaires

3
votes

Comme Jim Mischel mentionné - il est impossible de faire une recherche unique pour la modification de la valeur de l'article du dictionnaire. ConcurrentDrictionary.addorUpdate CODE> Méthode effectuez plusieurs opérations de recherche (sources réfléchies):

ConcurrentDictionary: 2504
Dictionary: 1351


0 commentaires

5
votes

Vous pouvez faire quelque chose comme ceci:

private class Counter
{
  public string Key       { get ; set ; }
  public int    Frequency { get ; set ; }
}

...

Dictionary<string,Counter> frequencyTable = new Dictionary<string,Counter>() ;

...

string someKey = GetKeyToLookup() ;
Counter item = null ;
bool hit = frequencyTable.TryGetValue( someKey,out item ) ;
if ( !hit )
{
  item = new Counter{ Key=someKey,Frequency=0 } ;
}
++ item.Frequency ;


3 commentaires

Oui, c'est exactement ce que je voulais dire par "un dictionnaire de références à des INT mutables est plus rapide" mais qui introduit des références inutiles, ce qui signifie des allocations de tas et d'écrire des barrières.


@Jonharrop l'avez-vous essayé? C5 est-il effectivement plus efficace pour cette tâche? Est la deuxième recherche ou le type de référence plus coûteux?


Je l'ai essayé avec mon propre code (pas C5) et le dictionnaire des références mutables était plus rapide que double recherche sur un dictionnaire de valeurs. La seconde recherche est plus chère. Cependant, un dictionnaire qui permet une complément serait la solution la plus rapide, bien sûr.