Mon blog à propos de programmation
Publié ou mis à jour le :
2013-12-31
Dispose parallèle et efficace (C#)
Dans .NET, pour chaque classe utilisée en parallèle (par plusieurs tâches, ou « thread safe » pour les anglophones) et implémentant IDisposable, il faut péniblement implémenter une méthode « Dispose » fonctionnant en parallèle aussi.
Ici je propose une petite structure qui nous facilite la vie, et qui en plus a le mérite d’être efficace: rapide et petite.
Code de la structure:
internal struct DisposeParallèle { enum LibéréOuPas { PasEncoreSupprimé, DéjàSupprimé } int déjàSuppriméOuPas; internal void Dispose(Action MéthodeDeSuppression) { // "Interlocked" est bien plus rapide que "lock". LibéréOuPas l = (LibéréOuPas) System.Threading.Interlocked.CompareExchange( ref this.déjàSuppriméOuPas, (int)LibéréOuPas.DéjàSupprimé, (int) LibéréOuPas.PasEncoreSupprimé); // Ici, "déjàSuppriméOuPas" a toujours pour valeur DéjàSupprimé, et il n'en changera plus. if (l == LibéréOuPas.PasEncoreSupprimé) MéthodeDeSuppression(); } }
Remarques:
- On utilise « Interlocked », qui est bien plus rapide que « lock ».
La preuve: http://www.drdobbs.com/windows/boosting-performance-with-atomic-operati/226900048 - On se contente de mémoriser un simple entier 32 bits, là où un « lock » aurait nécessité un objet et un booléen.
J’aurais aimé ne mémoriser qu’un booléen, d’ailleurs, mais « Interlocked » ne propose pas de méthode « CompareExchange » sur un booléen. - En tant que simple structure, on économise les ressources objets, et on n’a pas besoin d’appeler un constructeur.
Exemple d’utilisation:
internal class MaClasse : IDisposable { DisposeParallèle disposeParallèle; void IDisposable.Dispose() { this.disposeParallèle.Dispose(this.suppression); } void suppression() { // votre code... } ~MaClasse() // si nécessaire { ((IDisposable)this).Dispose(); } }
Ça reste assez simple à utiliser, avec un code bien découpé donc facile à maintenir.