По какой-то причине кажется, что операция Add
на HashSet
медленнее, чем операция Contains
, когда элемент уже существует в HashSet
.
Вот доказательство:
Stopwatch watch = new Stopwatch();
int size = 10000;
int iterations = 10000;
var s = new HashSet<int>();
for (int i = 0; i < size; i++) {
s.Add(i);
}
Console.WriteLine(watch.Time(() =>
{
for (int i = 0; i < size; i++) {
s.Add(i);
}
}, iterations));
s = new HashSet<int>();
for (int i = 0; i < size; i++) {
s.Add(i);
}
// outputs: 47,074,764
Console.WriteLine(watch.Time(() =>
{
for (int i = 0; i < size; i++) {
if (!s.Contains(i))
s.Add(i);
}
}, iterations));
// outputs: 41,125,219
Почему Contains
быстрее, чем Add
для уже существующих элементов?
Примечание. Я использую это расширение Stopwatch
из другого вопроса SO.
public static long Time(this Stopwatch sw, Action action, int iterations) {
sw.Reset();
sw.Start();
for (int i = 0; i < iterations; i++) {
action();
}
sw.Stop();
return sw.ElapsedTicks;
}
UPDATE. Внутреннее тестирование показало, что большая производительность diff происходит только в x64-версии .NET framework. С 32-разрядной версией Framework Содержит, кажется, запускается с одинаковой скоростью для добавления (на самом деле кажется, что версия с содержимым в некоторых тестовых прогонах работает на более медленном уровне). В версиях X64 версии Framework версия с содержимым кажется работают на 15% быстрее.