8

jestem w stanie rozwiązać mój ConcurrentDictionary wartością tak:Sortowanie ConcurrentDictionary przez wartość

static ConcurrentDictionary<string, Proxy> Proxies = 
    new ConcurrentDictionary<string, Proxy>(); 

Proxies.OrderBy(p => p.Value.Speed); 

Które jest super, z wyjątkiem chcę ustawić tę nową listę ponownego zamawiać słownika, skutecznie sortowania słownika zamiast odbierać listę wyników posortowanych przedmiotów.

staram się zrobić coś takiego, ale nie miał szczęścia - słownik jest nadal nieuporządkowana po:

Proxies = new ConcurrentDictionary<string,Proxy>(
    Proxies.OrderBy(p => p.Value.Speed)); 

Wydaje się, że robi to nie ma wpływu na słownika. Próbowałem też rzucić wynik OrderBy na nowy var, myśląc, że może to mieć wpływ na delegata, ale wciąż nie ma szczęścia.

Jak mogę zmienić kolejność tego ConcurrentDictionary, a następnie wymusić, aby słownik był ponownie zamówionym wynikiem z OrderBy?

+0

Jeśli potrzebujesz szybkich właściwości dostępu słownika, w połączeniu z wątku bezpieczeństwa i ciągłego sortowania, trzeba coś takiego współbieżne drzewo B. Nie wierzę, że jest jeden dostępny w .NET. Być może trzecia strona? Czy jest szansa, że ​​po prostu użyjesz funkcji OrderBy(), gdy potrzebujesz wyników? – Timo

Odpowiedz

6

Słowniki proste nie są posortowane kolekcje. Są po prostu zbiorem mapującym klucze do wartości. ConcurrentDictionary nie jest inaczej.

Zamiast tego potrzebowałbyś SortedConcurrentDictionary (pokrewnej do SortedDictionary), jednak ta struktura danych nie istnieje.

Jeśli rzeczywiście potrzebujesz posortowanego "słownika", powinniśmy dowiedzieć się więcej o Twoim przypadku użycia. Czy jest to kolejka priorytetowa? Czy mógłbyś po prostu użyć ConcurrentBag<Proxy> i dokonać porządkowania po fakcie?

Jeśli chcesz pobrać kolekcję, a następnie w równoległej metodzie, użyj proxy w porządku posortowanym, proponuję przyjrzeć się tworzeniu custom Partitioner, potencjalnie pożyczając od MSDN example of an OrderablePartitioner.

+0

Słownik był używany tylko w celu uniknięcia dodawania duplikatów wartości. Wcześniej po prostu używałem listy i sprawdzania, czy wartości istniały przed dodaniem. Mogę użyć ConcurrentBag , ale wymagałoby to użycia dwóch oddzielnych list, ponieważ zachowam aktywnie widoczny i utrzymany widok serwerów proxy w widoku listy, umożliwiając wyświetlanie/zarządzanie serwerami proxy/etc. Poprzednia implementacja Listy z mechanizmami blokującymi działała całkiem dobrze, dopóki nie dotarłem do błędu ostatnio z obecnymi zerowymi elementami, więc próbowałem przełączać się na ConcurrentBag/Dictionary/etc ... – user1111380

+0

Więc brzmi, jakbyś potrzebował współbieżnego ' HashSet', którego 'ConcurrentBag' nie jest taki, jaki znalazłeś. Czy to jest współbieżne, ponieważ pojawia się inny wątek i aktualizuje go? – user7116

+0

Rgiht, używam wielu wątków, aby sprawdzić proxy i zaktualizować listę odpowiednio. – user1111380

0

ConcurrentDictionary, podobnie jak Dictionary, nie zna koncepcji sortowania, tj. Nie zawiera żadnych informacji o zamówieniu. Wynik OrderBy() ma określoną kolejność, ale po przypisaniu do Proxies informacje o zamówieniu zostaną utracone.

Należy zauważyć, że istnieją posortowane implementacje IDictionary, a mianowicie SortedDictionary i SortedList.

+0

Z pewnością jest to problem, który może zbadać zespół BCL? – Eniola

2

Słownik, w szczególności ConcurrentDictionary, jest w zasadzie nieposortowany.

Jeśli potrzebujesz sortowanej kolekcji, musisz zapisać wartości w innym typie, na przykład SortedDictionary<T,U>.

+0

Mam nadzieję, że wykorzystam wbudowaną współbieżność .NET oferowaną przez ConcurrentDictionary. Widzę, że nie jest to możliwe, oferując posortowane możliwości. Powrót do korzystania z instrukcji lock() ... dzięki. – user1111380

+1

@ user1111380 Po prostu bądź ostrożny - zamawianie i równoczesne kolekcje zwykle kolidują z ... Zazwyczaj (o ile jest to możliwe) dobrze jest zachować dane w zbieraniu zbieżności podczas pracy nad nim, a następnie wyodrębnić elementy w określonej kolejności, aby przedstawić wyniki itp. –

+0

Jednak pobieranie przedmiotów w określonej kolejności, w której praca z kolekcją jest bardziej intensywna, niż intensywne pisanie, może być dość kosztowne. Widzę przypadek, dla którego chciałbym zaktualizować ConcurrentDictionary i sortowanie elementów powinno być atomowo częścią aktualizacji. Zamiast reinicjalizować cały słownik w żądanej kolejności sortowania. W tym celu, ConcurrentSortedDictionary lub SortedConcurrentDictionary będzie miło mieć w BCL. – Eniola

2

Rozwiązaniem jest użycie SortedSet<T>, odkrytego po wielu godzinach badań i rewizji kodu. Sortowany zestaw oferuje unikatowość modelu Dictionary lub HashSet, ale także umożliwia sortowanie - ani Dictionary ani Dictionary ani nie pozwalają na sortowanie.

+2

Z tym, że SortedSet nie jest równoczesny? Myślę, że posiadanie kolekcji, która obsługuje sortowanie i jest równoległa, jest istotnym elementem w naszej torbie narzędziowej. Sądzę, że powinniśmy zachęcić zespół BCL, żeby się temu przyjrzał. – Eniola

1

Może nie skuteczny jeśli nazywają go często w niezmiennej klasy, ale prosta:

Imports System.Collections.Concurrent 

Public Class SortedConcurrentDictionary(Of TKey, Tvalue) 
Inherits ConcurrentDictionary(Of TKey, Tvalue) 

    Shadows ReadOnly Property Values As IEnumerable(Of Tvalue) 
     Get 
      If MyBase.Values.Count = 0 Then 
       Return MyBase.Values 
      End If 
      Return From k In Keys Order By k Select Me(k) 
     End Get 
    End Property 
End Class 
+0

Interesujący pomysł, ale jak wydajne jest to? Wydaje się, że klucze są sortowane na każdym wyliczeniu zawartości? – Eniola

+0

@Eniola Masz całkowitą rację, jak powiedziałem: "Może nie jest to skuteczne". Bardziej wyrafinowana wersja buforowałaby i odświeżała pamięć podręczną po zmianie definicji ditionarii. – smirkingman

Powiązane problemy