Domanda

Sto cercando di ottimizzare una raccolta simultanea che cerca di minimizzare contesa dei blocchi per legge. Primo passaggio stava usando una lista collegata, che mi ha permesso di bloccare solo su operazioni di scrittura mentre molti simultanea legge potrebbe continuare sbloccato. Questo era un IEnumerator personalizzata per yield il prossimo valore di collegamento. Una volta ho iniziato a confronto l'iterazione sulla raccolta ad un List<T> pianura ho notato mia implementazione era circa la metà più veloce (per from x in c select x su una collezione di 1 * articoli M *, ho ottenuto 24ms per List<T> e 49ms per la mia collezione).

Così ho pensato di utilizzare un ReaderWriteLockSlim e sacrificare un po 'di contesa sul recita così ho potuto utilizzare un List<T> come la mia memoria interna. Dal momento che ho per catturare il blocco di lettura in fase di start iterazione e rilasciarlo al termine, ho fatto un modello di rendimento per il mio IEnumerable, foreach ing sul List<T> interna. Ora mi è stato sempre solo 66ms .

Ho dato un'occhiata a ciò che realmente fa List e utilizza un negozio interno di T[] e un IEnumerator personalizzato che si muove in avanti l'indice e restituisce il valore dell'indice corrente. Ora, utilizzando manualmente T[] come storage significa molto più lavoro di manutenzione, ma wth , sto inseguendo microsecondi.

Tuttavia, anche imitando il movimento IEnumerator l'indice su un array, il meglio che potessi fare era di circa ~ 38ms . Quindi, ciò che dà List<T> sua salsa segreta o, in alternativa qual è un'implementazione veloce per un iteratore?

UPDATE: Si scopre che il mio principale colpevole velocità era in esecuzione di debug di compilazione, mentre List<T> è, ovviamente, una compilazione di uscita. Nel rilascio mia implementazione è ancora un pelo più lento di List<T>, benche il mono è ora più veloce.

Un altro suggerimento che ho ottenuto da un amico è che la BCL è più veloce perché è in GAC e quindi può ottenere pre-compilato da parte del sistema. Dovrà mettere la mia prova nel GAC per testare questa teoria.

È stato utile?

Soluzione

Acquisizione e rilasciando il blocco su ogni iterazione suona come una cattiva idea - perché se si esegue un Add o Remove mentre si sta scorrendo sopra la lista, che invaliderà l'iteratore. List<T> certamente non vorrebbe che, per esempio.

sarebbe il vostro caso d'uso consentire ai chiamanti di stipulare un ReaderWriterLockSlim intorno tutto il loro processo di iterazione, invece che su una base per-articolo? Sarebbe più efficiente e più robusto. Se no, come hai intenzione di affrontare la questione della concorrenza? Se uno scrittore aggiunge un elemento prima di quanto il luogo in cui ho avuto modo di, una semplice implementazione sarebbe tornato lo stesso elemento due volte. L'opposto accadrebbe con una rimozione -. All'iteratore sarebbe escluso un elemento

Infine, è NET 4.0 un'opzione? So che ci sono alcune collezioni simultanei altamente ottimizzati lì ...

EDIT: Io non sono abbastanza sicuro che cosa la vostra situazione attuale è in termini di costruzione di un iteratore a mano, ma una cosa che si potrebbe desiderare di indagare sta usando una struct per il IEnumerator<T>, e rendere la vostra collezione esplicitamente dichiarare che restituisce che - questo è ciò che fa List<T>. E ' non significa utilizzando una struttura mutevole, che rende i gattini piangere tutto il mondo, ma se questo è assolutamente cruciale per le prestazioni e si pensa che si può vivere con l'orrore, è almeno la pena di provare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top