8

sono in grado di ordinare il mio ConcurrentDictionary per valore in questo modo:Ordinamento di una ConcurrentDictionary da Value

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

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

Che è grande, tranne che voglio impostare quella nuova lista riordinata AS dizionario, l'ordinamento in modo efficace il dizionario stesso piuttosto che ricevere solo un elenco di risultati di elementi ordinati.

provo a fare qualcosa di simile, ma non ha avuto fortuna - il dizionario è ancora ordinata dopo:

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

Sembra di fare che non ha alcun effetto sul dizionario. Ho anche provato a trasmettere il risultato OrderBy a un nuovo var pensando che potrebbe avere un effetto sul delegato ma ancora senza fortuna.

Come posso riordinare questo ConcurrentDictionary e quindi forzare il dizionario a essere il risultato riordinato da OrderBy?

+0

Se avete bisogno le proprietà di accesso veloce di un dizionario, in combinazione con thread-sicurezza e ordinamento continua, è necessario qualcosa di simile un B-albero concorrente. Non credo che ce ne sia uno prontamente disponibile in .NET. Forse una terza parte? Qualche possibilità che tu possa usare OrderBy() quando hai bisogno dei risultati? – Timo

risposta

6

I dizionari semplici non sono raccolte ordinate. Sono semplicemente una raccolta che mappa le chiavi dei valori. ConcurrentDictionary non è diverso.

Avresti invece bisogno di un SortedConcurrentDictionary (simile a SortedDictionary), tuttavia, questa struttura dati non esiste.

Per quanto riguarda se effettivamente si richiede un "dizionario" ordinato, avremmo bisogno di saperne di più sul tuo caso d'uso. Questa è una coda di priorità faux? Potresti semplicemente usare un ConcurrentBag<Proxy> ed eseguire gli ordini dopo il fatto?

Se è necessario prendere la raccolta e in un metodo parallelo a valle utilizzare i proxy in ordine ordinato, suggerisco di dare un'occhiata a creare uno custom Partitioner, potenzialmente prendendo in prestito dallo MSDN example of an OrderablePartitioner.

+0

Il dizionario è stato utilizzato solo per impedire l'aggiunta di valori duplicati. In precedenza, stavo semplicemente usando un elenco e controllando se i valori esistevano prima di aggiungere. Potrei usare una ConcurrentBag ma ciò richiederebbe l'utilizzo di due elenchi separati poiché mantengo una visualizzazione attiva e visibile dei proxy in un controllo ListView, consentendo la visualizzazione/gestione dei proxy/ecc. La precedente implementazione dell'Elenco con meccanismi di blocco funzionava abbastanza bene fino a quando non ho raggiunto un bug di recente con elementi null presenti, quindi ho provato a passare a ConcurrentBag/Dictionary/etc ... – user1111380

+0

Quindi sembra che tu abbia bisogno di un concurrent ' HashSet', che il 'ConcurrentBag' non è come hai trovato. È concomitante perché viene fornito un altro thread e lo aggiorna? – user7116

+0

Rgiht, sto usando più thread per controllare i proxy e aggiornare l'elenco di conseguenza. – user1111380

0

ConcurrentDictionary, proprio come Dictionary, non conosce il concetto di ordinamento, cioè non contiene alcuna informazione di ordinazione. Il risultato di OrderBy() ha un ordine specifico, ma se assegnato a Proxies, le informazioni dell'ordine vengono perse.

Si noti che esistono implementazioni ordinate di IDictionary, ovvero SortedDictionary e SortedList.

+0

Certamente questo è un problema che il team BCL può esaminare? – Eniola

2

Un dizionario, in particolare ConcurrentDictionary, è essenzialmente non ordinato.

Se è necessaria una raccolta ordinata, è necessario memorizzare i valori in un altro tipo, ad esempio SortedDictionary<T,U>.

+0

Speravo di utilizzare la concorrenza .NET integrata offerta da ConcurrentDictionary, comunque. Posso vedere che questo non è possibile pur offrendo funzionalità ordinate. Torna alle istruzioni lock() ... grazie. – user1111380

+1

@ user1111380 Basta fare attenzione: le ordinazioni e le raccolte concorrenti di solito sono in conflitto ... In genere, (quando possibile) è una buona idea conservare i dati in una raccolta simultanea mentre ci si lavora, quindi estrarre gli articoli in un ordine specifico per presentare i risultati , ecc. –

+0

Ma recuperare gli elementi in un dato ordine in cui lavorare con la raccolta è più intensivo in termini di lettura rispetto alla scrittura intensiva può essere piuttosto costoso. Vedo un caso per voler aggiornare un ConcurrentDictionary e fare in modo che l'ordinamento degli oggetti sia atomicamente parte dell'aggiornamento. Piuttosto che dover reinizializzare l'intero dizionario nell'ordine di ordinamento desiderato. A tal fine, ConcurrentSortedDictionary o SortedConcurrentDictionary sarà piacevole da avere nel BCL. – Eniola

2

La soluzione è utilizzare uno SortedSet<T>, scoperto dopo molte ore di ricerca e revisione del codice. Un set ordinato offre l'esclusività di uno Dictionary o HashSet, ma consente anche l'ordinamento - né uno Dictionary né un HashSet consentono l'ordinamento.

+2

Tranne che un SortedSet non è simultaneo? Penso che avere una collezione che supporti l'ordinamento e sia concomitante sia un elemento essenziale nella nostra borsa degli attrezzi. Penso che dovremmo incoraggiare la squadra BCL a dare un'occhiata a questo. – Eniola

1

Forse non è efficiente se si chiama spesso in una classe immutabile, ma semplice:

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

Idea interessante, ma quanto è performante? Sembra che le chiavi siano ordinate su ogni enumerazione dei contenuti? – Eniola

+0

@Eniola Hai perfettamente ragione, come ho detto, "Forse non efficiente". Una versione più sofisticata memorizza nella cache e aggiorna la cache quando viene modificato il ditionary. – smirkingman

Problemi correlati