Peut-être que j'ai manqué quelque chose, mais je suis sûr que tes repères sont éteints.
J'ai testé avec les méthodes suivantes:
- L'
Any
méthode d'extension ("LINQ")
- Un simple
foreach
boucle (votre "optimisé" de la méthode)
- À l'aide de l'
ICollection.Contains
méthode
- L'
Any
méthode d'extension à l'aide d'une optimisation de structure de données (HashSet<T>
)
Voici le code de test:
class Program
{
static void Main(string[] args)
{
var names = Enumerable.Range(1, 10000).Select(i => i.ToString()).ToList();
var namesHash = new HashSet<string>(names);
string testName = "9999";
for (int i = 0; i < 10; i++)
{
Profiler.ReportRunningTimes(new Dictionary<string, Action>()
{
{ "Enumerable.Any", () => ExecuteContains(names, testName, ContainsAny) },
{ "ICollection.Contains", () => ExecuteContains(names, testName, ContainsCollection) },
{ "Foreach Loop", () => ExecuteContains(names, testName, ContainsLoop) },
{ "HashSet", () => ExecuteContains(namesHash, testName, ContainsCollection) }
},
(s, ts) => Console.WriteLine("{0, 20}: {1}", s, ts), 10000);
Console.WriteLine();
}
Console.ReadLine();
}
static bool ContainsAny(ICollection<string> names, string name)
{
return names.Any(s => s == name);
}
static bool ContainsCollection(ICollection<string> names, string name)
{
return names.Contains(name);
}
static bool ContainsLoop(ICollection<string> names, string name)
{
foreach (var currentName in names)
{
if (currentName == name)
return true;
}
return false;
}
static void ExecuteContains(ICollection<string> names, string name,
Func<ICollection<string>, string, bool> containsFunc)
{
if (containsFunc(names, name))
Trace.WriteLine("Found element in list.");
}
}
Ne vous inquiétez pas sur le fonctionnement interne de l' Profiler
classe. Il fonctionne juste l' Action
dans une boucle et utilise un Stopwatch
du temps. Elle fait également en sorte d'appeler GC.Collect()
avant chaque test afin d'éliminer autant de bruit que possible.
Voici les résultats:
Enumerable.Any: 00:00:03.4228475
ICollection.Contains: 00:00:01.5884240
Foreach Loop: 00:00:03.0360391
HashSet: 00:00:00.0016518
Enumerable.Any: 00:00:03.4037930
ICollection.Contains: 00:00:01.5918984
Foreach Loop: 00:00:03.0306881
HashSet: 00:00:00.0010133
Enumerable.Any: 00:00:03.4148203
ICollection.Contains: 00:00:01.5855388
Foreach Loop: 00:00:03.0279685
HashSet: 00:00:00.0010481
Enumerable.Any: 00:00:03.4101247
ICollection.Contains: 00:00:01.5842384
Foreach Loop: 00:00:03.0234608
HashSet: 00:00:00.0010258
Enumerable.Any: 00:00:03.4018359
ICollection.Contains: 00:00:01.5902487
Foreach Loop: 00:00:03.0312421
HashSet: 00:00:00.0010222
Les données sont très cohérente et raconte l'histoire suivante:
Naïvement à l'aide de l' Any
méthode d'extension est d'environ 9% plus lent que naïvement à l'aide d'un foreach
boucle.
À l'aide de la méthode la plus appropriée (ICollection<string>.Contains
) avec un unoptimized structure de données (List<string>
) est environ 50% plus rapide que naïvement à l'aide d'un foreach
boucle.
À l'aide d'une optimisation de structure de données (HashSet<string>
) souffle complètement l'une des méthodes hors de l'eau en termes de performances.
Je n'ai aucune idée de l'endroit où vous avez obtenu 243%. Ma conjecture est qu'il a quelque chose à faire avec tout ce casting. Si vous utilisez un ArrayList
alors non seulement vous à l'aide d'un unoptimized structure de données, vous êtes en utilisant une grande partie obsolète structure de données.
Je peux prévoir ce qui vient ensuite. "Ouais, je sais que vous pouvez l'optimiser un peu mieux, mais c'était juste un exemple pour comparer la performance de LINQ vs non-LINQ."
Ouais, mais si vous ne pouvait pas encore être approfondie dans votre exemple, comment peut-on s'attendre à l'être approfondie dans le code de production?
La ligne de fond est:est-ce
Comment vous l'architecte et la conception de votre logiciel est considérablement plus important que ce que les outils spécifiques que vous utilisez et quand.
Si vous exécutez dans les goulets d'étranglement de performance - qui est tout aussi susceptible de se produire avec LINQ vs sans - puis à les résoudre. Eric suggestion de traitement automatisé de tests de performance est excellente; qui va vous aider à identifier les problèmes précoce de sorte que vous pouvez les résoudre correctement - pas en fuyant un outil étonnant qui vous fait 80% plus productif, mais il arrive à subir une < 10% de la performance, mais en fait, l' enquête sur la question et à venir avec une solution qui peut booster vos performances par un facteur de 2, ou 10, ou 100 ou plus.
La création des applications de haute performance n'est pas à propos de l'utilisation du droit de bibliothèques. C'est à propos de profilage, à faire de bons choix de conception, et la rédaction d'un bon code.