Avant que je commence un projet, j'ai écrit un test simple pour comparer les performances de ConcurrentBag d' (Système d'.Les Collections.En même temps) par rapport à verrouillage & listes. Je suis extrêmement surpris que ConcurrentBag est plus de 10 fois plus lent que le verrouillage avec une simple Liste. Ce que je comprends, le ConcurrentBag fonctionne mieux lorsque le lecteur et l'écrivain est le même thread. Cependant, je n'avais pas pensé que ça serait tellement pire que les serrures traditionnelles.
J'ai lancer un test avec deux Parallèles pour les boucles d'écriture et de lecture à partir d'une liste/sac. Cependant, l'écriture en elle-même montre une énorme différence:
private static void ConcurrentBagTest()
{
int collSize = 10000000;
Stopwatch stopWatch = new Stopwatch();
ConcurrentBag<int> bag1 = new ConcurrentBag<int>();
stopWatch.Start();
Parallel.For(0, collSize, delegate(int i)
{
bag1.Add(i);
});
stopWatch.Stop();
Console.WriteLine("Elapsed Time = {0}",
stopWatch.Elapsed.TotalSeconds);
}
Sur ma boîte, cela prend entre 3-4 secondes pour exécuter, par rapport à 0.5 - 0.9 secondes de ce code:
private static void LockCollTest()
{
int collSize = 10000000;
object list1_lock=new object();
List<int> lst1 = new List<int>(collSize);
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
Parallel.For(0, collSize, delegate(int i)
{
lock(list1_lock)
{
lst1.Add(i);
}
});
stopWatch.Stop();
Console.WriteLine("Elapsed = {0}",
stopWatch.Elapsed.TotalSeconds);
}
Comme je l'ai mentionné, en faisant des lectures et écritures simultanées n'aide pas la concurrente de sac de test. Suis-je en train de faire quelque chose de mal ou est-ce la structure de données vraiment lent?
[EDIT] - j'ai enlevé les Tâches parce que je n'ai pas besoin d'eux ici (code Complet avait une autre tâche de lecture)
[MODIFIER] Merci beaucoup pour les réponses. Je vais avoir du mal à choisir "la bonne réponse", car elle semble être un mélange d'un peu de réponses.
Comme Michael Goldshteyn souligné, la vitesse dépend vraiment de données. Darin a souligné qu'il devrait y avoir plus de contention pour ConcurrentBag pour être plus rapide, et en Parallèle.Pour ne pas nécessairement commencer le même nombre de threads. Un point à retenir est de ne pas faire quelque chose que vous ne pas avoir à l'intérieur d'une serrure. Dans le cas ci-dessus, je ne me vois pas faire quelque chose à l'intérieur de la serrure à l'exception peut-être de l'affectation de la valeur d'une variable temp.
En outre, sixlettervariables a souligné que le nombre de threads qui se trouvent être en cours d'exécution peut également affecter les résultats, bien que j'ai essayé de courir à l'origine du test dans l'ordre inverse et ConcurrentBag était encore plus lent.
J'ai couru quelques tests à partir du 15 Tâches et les résultats dépendait de la taille de la collection, entre autres choses. Cependant, ConcurrentBag fait presque aussi bien ou mieux que le verrouillage d'une liste, jusqu'à 1 million d'insertions. Au-dessus de 1 million de dollars, verrouillage semblait être beaucoup plus rapide parfois, mais je vais probablement jamais à avoir un plus grand discbased pour mon projet. Voici le code que j'ai couru:
int collSize = 1000000;
object list1_lock=new object();
List<int> lst1 = new List<int>();
ConcurrentBag<int> concBag = new ConcurrentBag<int>();
int numTasks = 15;
int i = 0;
Stopwatch sWatch = new Stopwatch();
sWatch.Start();
//First, try locks
Task.WaitAll(Enumerable.Range(1, numTasks)
.Select(x => Task.Factory.StartNew(() =>
{
for (i = 0; i < collSize / numTasks; i++)
{
lock (list1_lock)
{
lst1.Add(x);
}
}
})).ToArray());
sWatch.Stop();
Console.WriteLine("lock test. Elapsed = {0}",
sWatch.Elapsed.TotalSeconds);
// now try concurrentBag
sWatch.Restart();
Task.WaitAll(Enumerable.Range(1, numTasks).
Select(x => Task.Factory.StartNew(() =>
{
for (i = 0; i < collSize / numTasks; i++)
{
concBag.Add(x);
}
})).ToArray());
sWatch.Stop();
Console.WriteLine("Conc Bag test. Elapsed = {0}",
sWatch.Elapsed.TotalSeconds);