none
Is there a thread-save multi-key dictionary out there? RRS feed

  • Frage

  • Hello fellow developers,

    what I am looking for is something like a [attn:draft]

     

    MultiDimensionalConcurrentDictionary<params T1[], T2>

     

    For the Math people among us, it'd be a multi-dimensional matrix with an arbitrary type for the indices.

    I do not need like 1000 dimensions, especially not when it comes to performance issues, but what I do need is to cut arbitrary m-dimensional slices, like this:

     

    var cd = new MultiDimensionalConcurrentDictionary<string, MyFancyClass>();
    cd.Add("foo", "bar", "ney", "yay", fancyClassInstance1);
    cd.Add("foo", "barn", "bud", "yay", fanceClassInstance2);
    cd.Add("foo", "bar", "fan", "cy", fancyClassInstance3);
    cd["foo"] -> { fancyClassInstance1, fancyClassInstance2 }
    cd["foo", "bar", null, null] -> { fancyClassInstance1, fancyClassInstance3 }
    cd["foo", "bar"] -> { fancyClassInstance1, fancyClassInstance3 }
    cd["foo", null, null, "yay"] -> { fancyClassInstance1, fancyClassInstance2 }
    
    
    but of course

     

    cd["foo", "yay"] -> null or {}.Length == 0
    I tried to implement such a beast, but I gave up lately because performance sucked like... because I used .ToList() and that guy turned out to be a bottleneck.

     

    Any hint appreciated!



    • Bearbeitet CPosingies Dienstag, 27. Dezember 2011 17:49
    Dienstag, 27. Dezember 2011 17:42

Antworten

  • Hallo CPosingies,

    das lässt sich fast alles auf der Basis der von mir vorgeschlagenen Klassen realisieren. Als Hauptherausforderung würde ich hier die unscharfe Suche ansehen, die du etweder selbst in einer eigens gestrickten Collection implementieren musst, oder diese beim ersten (und nur beim ersten) Zugriff über eine Datenbank in deine Collection übernimmst.

    Der Weg über eine Datenbank dürfte der deutliche einfachrere sein. Dann wäre dein Schlüssel einfach ein string, der eine Liste von Schlüsselwerten darstellt (z.B. "2, 2, 2" anstelle von 2, 2, 2 oder "2, null, 2" anstelle von 2, null, 2). Von der Typsicherheit ist das natürlich nicht ganz so schön, dafür sind dann deine Schlüsselwerte sowohl inhaltlich als auch von der Länge her unschlagbar flexibel :)

    Ich hoffe, ich konnte dir weiterhelfen. Sollte du noch fragen haben...immer her damit.

    Viele Grüße
    Holger M. Rößler

     


    Kaum macht man es richtig, schon funktioniert es
    Donnerstag, 29. Dezember 2011 08:10

Alle Antworten

  • Hi CPosingies,

    dies ist ein deutschsprachiges Forum, daher Antworte ich auf deutsch.

    Wenn du .net 4.0 verwendest, findest du unter dem Namespace System.Collections.Concurrent eine Klasse namens ConcurrentDictionary<K,V> die eine threadsichere implementierung von System.Collection.Generic.Dictionary<K,V> darstellt.

    Für den Schlüssel könntest du die Tuple Klasse(n) bemühen (http://msdn.microsoft.com/de-de/library/dd387036.aspx). Solltest du was spezielleres benötigen, so gib mir bitte bescheid, dann werden wir schon das richtige finden... ;)

    Viele Grüße
    Holger M. Rößler


    Kaum macht man es richtig, schon funktioniert es
    • Bearbeitet Holger M. Rößler Dienstag, 27. Dezember 2011 23:30 System.Collection --> System.Collections
    Dienstag, 27. Dezember 2011 23:29
  • Hallo Holger,

    ja, sorry, ich wollte eigentlich in das englischsprachige Forum posten, aber irgendwie hat mein Browser wohl ein paar Cookies verschluckt...

    Ich probier nochmal eine Erklärung. Vorab aber erstmal, dass er mir nicht um eine Art Jagged Array geht.

    Die Erklärung mache ich mal in drei Dimensionen, weil man sich das vielleicht einfach wie ein Koordinatensystem vorstellen kann. Dann kann ich mit

    P(x, y, z) genau einen Punkt beschreiben. Lasse ich eine Dimension weg, also

    G(x, y) oder G(x, z) oder G(y, z), erhalte ich eine Gerade (weil der dritte Index ja angibt, welchen Punkt ich auf dieser Gerade meine). Lasse ich noch eine Dimension weg

    E(x) oder E(y) oder E(z), erhalte ich entsprechend Ebenen.

    Das erstmal "metaphorisch". Bleiben wir mal bei drei "Dimensionen", "Indizes", Schlüsseln und machen eine Relation draus:

    1, 1, 1 sei "A"

    1, 1, 2 sei "B"

    1, 1, 3 sei "C"

    1, 2, 1 sei "D"

    1, 2, 2 sei "E"

    1, 2, 3 sei "F"

    Dann noch ein paar dazu:

    2, 2, 2 sei "X"

    3, 3, 3 sei "Y"

    So. Jetzt eine Get-Methode dazu:

    ...Get(params T[] keys);

    Auf geht's:

    ...Get(1, 1, 1) == "A" // oder von mir aus auch { "A" }

    ...Get(1, null, 1) == { "A", "D" }

    ...Get(null, 2, null) == { "D", "E", "F", "X" }

    dasselbe wie

    ...Get(null, 2) == { "D", "E", "F", "X" }

    ...Get(3, null, null) == { "Y" }

    dasselbe wie

    ...Get(3) == { "Y" }

    und

    ...Get(4) == {} // oder von mir aus auch null

     

    Also, mir geht es auch nicht um einen mathematisch sauberen Aufbau der Ergebnisse, also irgendwie geschachtelte Scheiben (die besagten Slices), die die Dimensionen wiedergeben.

    Bisher hatte ich das ganze Thema eigentlich immer nur mit 2 Schlüsseln, aber jetzt sitze ich gerade an einem Problemchen, wo es sehr wahrscheinlich 4 Schlüssel werden. So langsam schwant mir, dass ich besser daran wäre, irgendwie dynamisch ein DataSet zusammenzuschrauben und mehrspaltige PKs drauf zu werfen, nur ist das dann ja beim Schreiben nicht mehr thread-safe.

    Und wieso ich das alles nicht eiinfach einer relationalen Datenbank überlasse, die genau sowas ganz toll kann, ist genau schon die Begründung: das Ganze ist das Grundgerüst für einen Cache.

    Mittwoch, 28. Dezember 2011 20:51
  • Hallo CPosingies,

    das lässt sich fast alles auf der Basis der von mir vorgeschlagenen Klassen realisieren. Als Hauptherausforderung würde ich hier die unscharfe Suche ansehen, die du etweder selbst in einer eigens gestrickten Collection implementieren musst, oder diese beim ersten (und nur beim ersten) Zugriff über eine Datenbank in deine Collection übernimmst.

    Der Weg über eine Datenbank dürfte der deutliche einfachrere sein. Dann wäre dein Schlüssel einfach ein string, der eine Liste von Schlüsselwerten darstellt (z.B. "2, 2, 2" anstelle von 2, 2, 2 oder "2, null, 2" anstelle von 2, null, 2). Von der Typsicherheit ist das natürlich nicht ganz so schön, dafür sind dann deine Schlüsselwerte sowohl inhaltlich als auch von der Länge her unschlagbar flexibel :)

    Ich hoffe, ich konnte dir weiterhelfen. Sollte du noch fragen haben...immer her damit.

    Viele Grüße
    Holger M. Rößler

     


    Kaum macht man es richtig, schon funktioniert es
    Donnerstag, 29. Dezember 2011 08:10
  • Hallo CPosingies,

    Ich gehe davon aus, dass die Antwort Dir weitergeholfen hat.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert


    Robert Breitenhofer, MICROSOFT  Twitter Facebook
    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Mittwoch, 4. Januar 2012 13:03
    Moderator
  • Hallo Robert,

    ich belasse es mal als "beantwortet". Aber ein "ConcurrentDataSet" wäre eine hübsche Sache im Framework, dann ließe sich meine Anforderung nicht hübsch, aber robust realisieren.

    LG
    Carsten

    Dienstag, 10. Januar 2012 19:55