InstrumentationRegistry.getInstrumentation().context
является контекстом измерительного приложения. Из вашего утверждения вы хотите контекст целевого инструментария, который является val appContext = InstrumentationRegistry.getInstrumentation().targetContext
AddIfNotPresent делает дополнительное деление, которое Содержит, не работает. Смотрите на IL для, Содержит:
IL_000a: call instance int32 class System.Collections.Generic.HashSet`1<!T>::InternalGetHashCode(!0)
IL_000f: stloc.0
IL_0010: ldarg.0
IL_0011: ldfld int32[] class System.Collections.Generic.HashSet`1<!T>::m_buckets
IL_0016: ldloc.0
IL_0017: ldarg.0
IL_0018: ldfld int32[] class System.Collections.Generic.HashSet`1<!T>::m_buckets
IL_001d: ldlen
IL_001e: conv.i4
IL_001f: rem
IL_0020: ldelem.i4
IL_0021: ldc.i4.1
IL_0022: sub
IL_0023: stloc.1
Это вычисляет местоположение блока для хэш-кода. Результат сохраняется в местоположении локальной памяти 1.
AddIfNotPresent делает что-то подобное, но он также сохраняет вычисленное значение в местоположении 2, так, чтобы он мог вставить объект в хеш-таблицу в том положении, если объект не существует. Это делает то сохранение, потому что одно из местоположений изменяется позже в цикле, который идет, ища объект. Так или иначе вот соответствующие нормы для AddIfNotPresent:
IL_0011: call instance int32 class System.Collections.Generic.HashSet`1<!T>::InternalGetHashCode(!0)
IL_0016: stloc.0
IL_0017: ldloc.0
IL_0018: ldarg.0
IL_0019: ldfld int32[] class System.Collections.Generic.HashSet`1<!T>::m_buckets
IL_001e: ldlen
IL_001f: conv.i4
IL_0020: rem
IL_0021: stloc.1
IL_0022: ldarg.0
IL_0023: ldfld int32[] class System.Collections.Generic.HashSet`1<!T>::m_buckets
IL_0028: ldloc.0
IL_0029: ldarg.0
IL_002a: ldfld int32[] class System.Collections.Generic.HashSet`1<!T>::m_buckets
IL_002f: ldlen
IL_0030: conv.i4
IL_0031: rem
IL_0032: ldelem.i4
IL_0033: ldc.i4.1
IL_0034: sub
IL_0035: stloc.2
Так или иначе я думаю, что дополнительное деление - то, что вызывает, Добавляют для взятия большего количества времени, чем Содержит. На первый взгляд похоже, что дополнительное деление могло быть факторизовано, но я не могу сказать наверняка, не проводя немного больше времени, дешифровав IL.
Интересный, на моей машине (Dell Latitude D630, двухъядерные 2,2 ГГц) я получаю почти идентичные результаты для обоих тестов, если я не выполняю секундомер против a null
действие перед тестами. Например:
Я запускаю тесты с точным кодом, который Вы дали в вопросе:
Without Contains(): 8205794
With Contains(): 8207596
Если я изменяю код этим способом:
После:
Stopwatch watch = new Stopwatch();
int size = 10000;
int iterations = 10000;
Добавьте:
watch.Time(null, 0);
Мои результаты становятся:
Without Contains(): 8019129
With Contains(): 8275771
Это кажется мне как что-то нечетное, продолжается в Stopwatch
это вызывает эти колебания.
Мое предположение - то, что Вы запустили свой тест из Visual Studio, которая вызвала встраивание AddIfNotPresent
в Add
быть подавленным, таким образом, Вы видите результат дополнительного уровня абстракции в вызовах метода.
Если я компилирую и работаю из командной строки для удаления какого-либо обмана VS...
> csc /o+ /t:exe Program.cs
> Program.exe
... затем нет никакого различия в производительности.
Демонстрационные выводы (представитель большего числа тестов):
35036174
35153818
35225763
34862330
35047377
35033323