Задать вопрос

Почему реализация из коробки List и не только она быстрее, точной копии кода до 2 раз?

Почему метод list.Add быстрее чем точная копия, и таких классов уже много замечал, если там есть минимум 1 лишняя строчка c _version++? То есть дизассемблер показывает больше кода, а он быстрее, как так, загадка Жака Фреско .
Может что-то не учитываю в бенчмарке, хотя ничто не могло пойти не так. Получается есть скрытые оптимизации, а где про них узнать, вроде List не partical класс, значит точная копия должна так же работать.
public class ListMy
   {

       public int[] _items;
       public int _size;
       public int Count => _size; 
       public ListMy(int capacity = 4)
       {
           _items = new int[0];
       }

       public int capacity => _items.Length;
       [MethodImpl(MethodImplOptions.AggressiveInlining)]
       public void Add(int item)
       {
           int[] array = _items;
           int size = _size;
           if ((uint)size < (uint)array.Length)
           {
               _size = size + 1;
               array[size] = item;
           }
           else
           {
               AddWithResize(item);
           }
       }   
       // Non-inline from List.Add to improve its code quality as uncommon path
       [MethodImpl(MethodImplOptions.NoInlining)]
       private void AddWithResize(int item)
       {
           Debug.Assert(_size == _items.Length);
           int size = _size;
           grow( );
           _size = size + 1;
           _items[size] = item;
       }

       [MethodImpl(MethodImplOptions.AggressiveInlining)]
       private void grow()
       {
           int lastCount = _size;
           var t = new int[int.Max(lastCount * 2,4)];
           Array.Copy(_items, t, _items.Length);
           _items = t;

       }
/*
         public void RemoveByIndex(int index)
         {
// для коллекции не важен порядок элементов. удаляю в конец 
             _items[index] = _items[--_size]; 
             if ((_size) <= (capacity >> 2))
             {
                 int newLen = capacity >> 1;
                 var t = new int[newLen];
                 Array.Copy(_items, t, _size);
                 _items = t;
             }
         }
*/
/*
 var span = CollectionsMarshal.AsSpan(list_1);
 span[index] = span[span.Length - 1];
 if (list_1.Count <= (list_1.Capacity >> 2))
 {
     list_1.Capacity = list_1.Capacity >> 1;
 }  
     CollectionsMarshal.SetCount(list_1, list_1.Count - 1);
*/
}

но например метод RemoveByIndex ожидаемо быстрее чем так. Хотя если скалировать сколько там кода, то он должен был быть в раз 10 быстрее, а не в 2.

public class BenchmarkList
  {

      ListMy listMy;
      List<int> listNative;
      private int[] array;

      [IterationSetup]
      public void Setup() { 
          listMy = new ListMy();
          listNative = new List<int>(); 
      }
      public IEnumerable<object[]> args()
      {

          yield return new object[] { 1000 };
          yield return new object[] { 10_000 };
          yield return new object[] { 100_000 };
      }

      [Benchmark]
      [ArgumentsSource(nameof(args))]
      public void Test_ListMy(int a)
      { 
          for (int i = 0; i < a; i+=4)
          {
              listMy.Add(i);
              listMy.Add(i-1);
              listMy.Add(i+1);
              listMy.Add(2*i);
          }
      }
      [Benchmark]
      [ArgumentsSource(nameof(args))]
      public void Test_ListNative(int a)
      {
          for (int i = 0; i < a; i += 4)
          {
              listNative.Add(i);
              listNative.Add(i - 1);
              listNative.Add(i + 1);
              listNative.Add(2 * i);
          }
      }

Она часто быстрее, но иногда ровно такая же скорост, но хоть на 1% быстрее всегда, хотя там одну переменную итерируют.
Если там есть какие скрытые микро оптимизации по зарегистрированному имени типа, то можно ли как-то туда и свою встроить.

Так же проверял, для вставки случайных элементов по случайным адресам в пределах 10 индексов. что бы там на всякий случай simd оптимизации не случились, то же всегда быстрее на 10% и более процентов.
  • Вопрос задан
  • 1431 просмотр
Подписаться 5 Простой Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы