Question

Je suis en train d'optimiser une collection concurrente qui tente de minimiser les conflits de verrous pour les lectures. Premier passage utilisait une liste chaînée, qui m'a permis de verrouiller seulement écrit pendant de nombreuses lectures simultanées pourraient continuer débloquée. Cela a utilisé un IEnumerator personnalisé rendement la valeur suivante de lien. Une fois que j'ai commencé à comparer l'itération sur la collection à une List<T> plaine je remarqué que ma mise en œuvre était d'environ la moitié aussi vite (pour from x in c select x sur une collection de 1 * articles m *, je suis 24ms pour List<T> et 49ms pour ma collection).

Alors je pensais que j'utiliser un ReaderWriteLockSlim et sacrifie un peu de conflits sur se lit pour que je puisse utiliser un List<T> que mon stockage interne. Depuis que je dois saisir le verrou de lecture sur le début d'itération et relâchez à la fin, j'ai d'abord fait un modèle de rendement pour mon IEnumerable, foreach ing sur la List<T> interne. Maintenant, je recevais seulement 66ms .

Je jeté un œil à ce que la liste ne fait et il utilise un stockage interne de T[] et un IEnumerator personnalisé qui déplace l'index vers l'avant et retourne la valeur d'index en cours. Maintenant, manuellement à l'aide T[] comme un moyen de stockage beaucoup plus de travail d'entretien, mais wth , je suis la chasse microsecondes.

Cependant, même mimer l'IEnumerator déplacement de l'index sur un tableau, le mieux que je pouvais faire était sur ~ 38ms . Alors, que List<T> donne sa sauce secrète ou encore ce qui est une implémentation plus rapide pour un itérateur?

Mise à jour: Active mon principal coupable de vitesse a été en cours d'exécution de la compilation de débogage, alors que List<T> est évidemment une compilation de sortie. Dans la version ma mise en œuvre est encore un poil plus lent que List<T> barbante sur mono il est maintenant plus rapide.

Une autre suggestion que je suis d'un ami est que la BCL est plus rapide parce qu'il est dans le GAC et peut donc obtenir par le système de pré-compilé. Faudra mettre mon test dans le GAC pour tester cette théorie.

Était-ce utile?

La solution

L'acquisition et la libération du verrou sur chaque itération sonne comme une mauvaise idée - parce que si vous effectuez une Add ou Remove pendant que vous êtes itérer sur la liste, qui annule la iterator. List<T> ne serait certainement pas comme ça, par exemple.

permettrait à votre cas d'utilisation des appelants de prendre un ReaderWriterLockSlim autour de leur processus d'itération, plutôt que sur une base par article? Ce serait plus efficace et plus robuste. Sinon, comment comptez-vous faire face à la question de la concurrence? Si un auteur ajoute un élément plus tôt que l'endroit où je dois, une implémentation simple retournerait le même élément deux fois. Le contraire se passerait-il avec un retrait -. Itérateur sauterait un élément

Enfin, est une option .NET 4.0? Je sais qu'il ya là des collections simultanées hautement optimisées ...

EDIT: Je ne suis pas sûr de ce que votre situation actuelle est en termes de construction d'un itérateur à la main, mais une chose que vous pourriez vouloir étudier avec une struct pour le IEnumerator<T>, et faire de votre collection déclare explicitement que retourne que - c'est ce que List<T> fait. Il fait signifie l'aide d'un struct mutable, ce qui rend les chatons pleurent partout dans le monde, mais si cela est absolument crucial pour la performance et vous pensez que vous pouvez vivre avec l'horreur, il est au moins la peine d'essayer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top