Производительность массивов против списков

Скажите, что вам нужно иметь список/массив целых чисел, которые вам часто нужно перебирать, и я имею в виду очень часто. Причины могут быть разными, но сказать это в самом сердце внутренней петли обработки большого объема.

В общем, можно было бы выбрать использование списков (List) из-за их гибкости в размере. Кроме того, заявки на документацию msdn Списки используют массив внутри и должны выполняться так же быстро (быстрый просмотр с Reflector подтверждает это). Бесполезно, есть некоторые накладные расходы.

Кто-нибудь действительно измерил это? будет ли истребитель 6M раз через список принимать то же время, что и массив?

Ответ 1

Очень легко измерить...

В небольшом количестве кода обработки с жесткой петлей , где я знаю, что длина исправлена. Я использую массивы для этого крошечного бита микро-оптимизации; массивы могут быть незначительно быстрее , если используется индекс/для формы, но IIRC полагает, что это зависит от типа данных в массиве. Но если вы нуждаетесь для микро-оптимизации, сохраните его просто и используйте List<T> и т.д.

Конечно, это применимо только в том случае, если вы читаете все данные; словарь будет быстрее для поиска по ключевым словам.

Здесь мои результаты с использованием "int" (второе число - контрольная сумма для проверки того, что все они выполняли одну и ту же работу):

(отредактирован для исправления ошибок)

List/for: 1971ms (589725196)
Array/for: 1864ms (589725196)
List/foreach: 3054ms (589725196)
Array/foreach: 1860ms (589725196)

на основе испытательной установки:

using System;
using System.Collections.Generic;
using System.Diagnostics;
static class Program
{
    static void Main()
    {
        List<int> list = new List<int>(6000000);
        Random rand = new Random(12345);
        for (int i = 0; i < 6000000; i++)
        {
            list.Add(rand.Next(5000));
        }
        int[] arr = list.ToArray();

        int chk = 0;
        Stopwatch watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            int len = list.Count;
            for (int i = 0; i < len; i++)
            {
                chk += list[i];
            }
        }
        watch.Stop();
        Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            for (int i = 0; i < arr.Length; i++)
            {
                chk += arr[i];
            }
        }
        watch.Stop();
        Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in list)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in arr)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        Console.ReadLine();
    }
}

Ответ 2

Я думаю, что производительность будет очень похожей. Накладные расходы, связанные с использованием List vs Array, являются IMHO при добавлении элементов в список и когда список должен увеличивать размер массива, который он использует внутри, когда достигается емкость массива.

Предположим, что у вас есть список с емкостью 10, тогда список увеличит его емкость, как только вы захотите добавить 11-й элемент. Вы можете уменьшить влияние производительности, инициализируя Емкость списка до количества элементов, которые он будет удерживать.

Но для того, чтобы выяснить, выполняется ли итерация по списку так же быстро, как итерация по массиву, почему бы вам не сравнить его?

int numberOfElements = 6000000;

List<int> theList = new List<int> (numberOfElements);
int[] theArray = new int[numberOfElements];

for( int i = 0; i < numberOfElements; i++ )
{
    theList.Add (i);
    theArray[i] = i;
}

Stopwatch chrono = new Stopwatch ();

chrono.Start ();

int j;

 for( int i = 0; i < numberOfElements; i++ )
 {
     j = theList[i];
 }

 chrono.Stop ();
 Console.WriteLine (String.Format("iterating the List took {0} msec", chrono.ElapsedMilliseconds));

 chrono.Reset();

 chrono.Start();

 for( int i = 0; i < numberOfElements; i++ )
 {
     j = theArray[i];
 }

 chrono.Stop ();
 Console.WriteLine (String.Format("iterating the array took {0} msec", chrono.ElapsedMilliseconds));

 Console.ReadLine();

В моей системе; итерация по массиву заняла 33 мсек; итерация по списку заняла 66 мсек.

Честно говоря, я не ожидал, что вариация будет такой. Итак, я поместил свою итерацию в цикл: теперь я выполняю итерацию 1000 раз. Результаты:

итерация списка заняла 67146 мсек итерация массива заняла 40821 мсек

Теперь вариация уже не такая большая, но все же...

Поэтому я запустил .NET Reflector и получатель индексатора класса List, выглядит так:

public T get_Item(int index)
{
    if (index >= this._size)
    {
        ThrowHelper.ThrowArgumentOutOfRangeException();
    }
    return this._items[index];
}

Как вы можете видеть, при использовании индексатора списка List выполняет проверку того, не выходите ли вы из границ внутреннего массива. Эта дополнительная проверка поставляется со стоимостью.

Ответ 3

если вы просто получаете одно значение из (не в цикле), то оба проверяют границы (вы в управляемом коде помните), это просто список делает это дважды. См. Примечания позже, почему это, вероятно, не имеет большого значения.

Если вы используете свой собственный for (int int я = 0; я < x. [Length/Count]; я ++), то ключевое различие заключается в следующем:

  • Массив:
    • проверка границ удаляется
  • Списки
    • Выполняется проверка границ

Если вы используете foreach, тогда ключевое различие выглядит следующим образом:

  • Массив:
    • для управления итерацией не выделяется объект
    • проверка границ удаляется
  • Список через переменную, известную как List.
    • переменная управления итерацией размещена в стеке Выполняется проверка границ
  • Список через переменную, известную как IList.
    • переменная управления итерацией является выделенной кучей Выполняется проверка границ
    • также Списки значений не могут быть изменены во время foreach, тогда как массив может быть.

Проверка границ часто не имеет большого значения (особенно если вы находитесь на процессоре с глубоким конвейером и прогнозом ветвления - норма для большинства этих дней), но только ваше собственное профилирование может сказать вам, если это проблема. Если вы находитесь в частях своего кода, где избегаете распределения кучи (хорошими примерами являются библиотеки или реализация хэш-кодов), то при условии, что переменная набирается как List not IList, она избежит этой ошибки. Как всегда профиль, если это имеет значение.

Ответ 4

[См. также этот вопрос]

Я изменил ответ Marc, чтобы использовать фактические случайные числа и фактически выполнять ту же работу во всех случаях.

Результаты:

         for      foreach
Array : 1575ms     1575ms (+0%)
List  : 1630ms     2627ms (+61%)
         (+3%)     (+67%)

(Checksum: -1000038876)

Скомпилирован как выпуск под VS 2008 SP1. Работа без отладки на [email protected],.NET 3.5 SP1.

код:

class Program
{
    static void Main(string[] args)
    {
        List<int> list = new List<int>(6000000);
        Random rand = new Random(1);
        for (int i = 0; i < 6000000; i++)
        {
            list.Add(rand.Next());
        }
        int[] arr = list.ToArray();

        int chk = 0;
        Stopwatch watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            int len = list.Count;
            for (int i = 0; i < len; i++)
            {
                chk += list[i];
            }
        }
        watch.Stop();
        Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            int len = arr.Length;
            for (int i = 0; i < len; i++)
            {
                chk += arr[i];
            }
        }
        watch.Stop();
        Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in list)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in arr)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);
        Console.WriteLine();

        Console.ReadLine();
    }
}

Ответ 5

Короткий ответ:

цветное значение

Array vs List vs Linked List

Более подробный ответ вы найдете по следующей ссылке: fooobar.com/questions/10645/...

Ответ 6

Измерения хороши, но вы получите значительно разные результаты в зависимости от того, что вы делаете именно в своем внутреннем цикле. Измерьте свою ситуацию. Если вы используете многопоточность, это просто нетривиальная деятельность.

Ответ 7

В самом деле, если вы выполняете сложные вычисления внутри цикла, производительность индексатора индекса по сравнению с индексом списка может быть настолько незначительно мала, что в конечном итоге это не имеет значения.

Ответ 8

Не пытайтесь добавить емкость, увеличивая количество элементов.

Производительность

List For Add: 1ms
Array For Add: 2397ms

    Stopwatch watch;
        #region --> List For Add <--

        List<int> intList = new List<int>();
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 60000; rpt++)
        {
            intList.Add(rand.Next());
        }
        watch.Stop();
        Console.WriteLine("List For Add: {0}ms", watch.ElapsedMilliseconds);
        #endregion

        #region --> Array For Add <--

        int[] intArray = new int[0];
        watch = Stopwatch.StartNew();
        int sira = 0;
        for (int rpt = 0; rpt < 60000; rpt++)
        {
            sira += 1;
            Array.Resize(ref intArray, intArray.Length + 1);
            intArray[rpt] = rand.Next();

        }
        watch.Stop();
        Console.WriteLine("Array For Add: {0}ms", watch.ElapsedMilliseconds);

        #endregion

Ответ 9

Здесь используется тот, который использует словари, IEnumerable:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

static class Program
{
    static void Main()
    {
        List<int> list = new List<int>(6000000);

        for (int i = 0; i < 6000000; i++)
        {
                list.Add(i);
        }
        Console.WriteLine("Count: {0}", list.Count);

        int[] arr = list.ToArray();
        IEnumerable<int> Ienumerable = list.ToArray();
        Dictionary<int, bool> dict = list.ToDictionary(x => x, y => true);

        int chk = 0;
        Stopwatch watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            int len = list.Count;
            for (int i = 0; i < len; i++)
            {
                chk += list[i];
            }
        }
        watch.Stop();
        Console.WriteLine("List/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            for (int i = 0; i < arr.Length; i++)
            {
                chk += arr[i];
            }
        }
        watch.Stop();
        Console.WriteLine("Array/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in Ienumerable)
            {
                chk += i;
            }
        }

        Console.WriteLine("Ienumerable/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in dict.Keys)
            {
                chk += i;
            }
        }

        Console.WriteLine("Dict/for: {0}ms ({1})", watch.ElapsedMilliseconds, chk);


        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in list)
            {
                chk += i;
            }
        }

        watch.Stop();
        Console.WriteLine("List/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in arr)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("Array/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);



        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in Ienumerable)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("Ienumerable/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 100; rpt++)
        {
            foreach (int i in dict.Keys)
            {
                chk += i;
            }
        }
        watch.Stop();
        Console.WriteLine("Dict/foreach: {0}ms ({1})", watch.ElapsedMilliseconds, chk);

        Console.ReadLine();
    }
}

Ответ 10

Поскольку List < > использует внутренние массивы, базовая производительность должна быть одинаковой. Две причины, почему Список может быть немного медленнее:

  • Чтобы найти элемент в списке, вызывается метод List, который выполняет поиск в базовом массиве. Поэтому вам нужен дополнительный метод. С другой стороны, компилятор может распознать это и оптимизировать "ненужный" вызов.
  • Компилятор может сделать некоторые специальные оптимизации, если он знает размер массива, который он не может сделать для списка неизвестной длины. Это может привести к некоторому повышению производительности, если у вас есть только несколько элементов в вашем списке.

Чтобы проверить, не имеет ли значения для вас, вероятно, лучше всего настроить опубликованные функции синхронизации на список размера, который вы планируете использовать, и посмотреть, как результаты для вашего специального случая.

Ответ 11

Я был обеспокоен тем, что Benchmarks, опубликованные в других ответах, по-прежнему оставляют место для компилятора для оптимизации, исключения или объединения циклов, поэтому я написал один, который:

  • Используемые непредсказуемые входы (случайные)
  • Выполняет вычисление с результатом, напечатанным на консоли
  • Изменяет входные данные при каждом повторении

Результат, поскольку прямой массив имеет на 250% лучшую производительность, чем доступ к массиву, завернутому в IList:

  • Доступ к 1 миллиарду массивов: 4000 мс
  • 1 миллиард списков: 10000 мс
  • 100 миллионов обращений к массиву: 350 мс
  • 100 миллионов обращений к списку: 1000 мс

Здесь код:

static void Main(string[] args) {
  const int TestPointCount = 1000000;
  const int RepetitionCount = 1000;

  Stopwatch arrayTimer = new Stopwatch();
  Stopwatch listTimer = new Stopwatch();

  Point2[] points = new Point2[TestPointCount];
  var random = new Random();
  for (int index = 0; index < TestPointCount; ++index) {
    points[index].X = random.NextDouble();
    points[index].Y = random.NextDouble();
  }

  for (int repetition = 0; repetition <= RepetitionCount; ++repetition) {
    if (repetition > 0) { // first repetition is for cache warmup
      arrayTimer.Start();
    }
    doWorkOnArray(points);
    if (repetition > 0) { // first repetition is for cache warmup
      arrayTimer.Stop();
    }

    if (repetition > 0) { // first repetition is for cache warmup
      listTimer.Start();
    }
    doWorkOnList(points);
    if (repetition > 0) { // first repetition is for cache warmup
      listTimer.Stop();
    }
  }

  Console.WriteLine("Ignore this: " + points[0].X + points[0].Y);
  Console.WriteLine(
    string.Format(
      "{0} accesses on array took {1} ms",
      RepetitionCount * TestPointCount, arrayTimer.ElapsedMilliseconds
    )
  );
  Console.WriteLine(
    string.Format(
      "{0} accesses on list took {1} ms",
      RepetitionCount * TestPointCount, listTimer.ElapsedMilliseconds
    )
  );

}

private static void doWorkOnArray(Point2[] points) {
  var random = new Random();

  int pointCount = points.Length;

  Point2 accumulated = Point2.Zero;
  for (int index = 0; index < pointCount; ++index) {
    accumulated.X += points[index].X;
    accumulated.Y += points[index].Y;
  }

  accumulated /= pointCount;

  // make use of the result somewhere so the optimizer can't eliminate the loop
  // also modify the input collection so the optimizer can merge the repetition loop
  points[random.Next(0, pointCount)] = accumulated;
}

private static void doWorkOnList(IList<Point2> points) {
  var random = new Random();

  int pointCount = points.Count;

  Point2 accumulated = Point2.Zero;
  for (int index = 0; index < pointCount; ++index) {
    accumulated.X += points[index].X;
    accumulated.Y += points[index].Y;
  }

  accumulated /= pointCount;

  // make use of the result somewhere so the optimizer can't eliminate the loop
  // also modify the input collection so the optimizer can merge the repetition loop
  points[random.Next(0, pointCount)] = accumulated;
}

Ответ 12

Поскольку у меня был аналогичный вопрос, это ускорило меня.

Мой вопрос немного конкретнее: "Какой самый быстрый метод для реализации рефлексивного массива"

Тестирование, выполненное Марком Гравелем, показывает много, но не точное время доступа. Его время включает в себя цикл по массиву и списки. Поскольку я также придумал третий метод, который я хотел протестировать, "Словарь", просто для сравнения, я расширил тестовый код.

Firts, я делаю тест с использованием константы, которая дает мне определенное время, включая цикл. Это "голое" время, исключая фактический доступ. Затем я делаю тест с доступом к структуре субъекта, это дает мне и "накладные расходы", время, цикл и фактический доступ.

Разница между "голым" временем и "временной задержкой" дает мне указание на время доступа к структуре.

Но насколько точно это время? Во время тестирования окна будут делать некоторое время нарезки для shure. У меня нет информации о разрезе времени, но я полагаю, что он равномерно распределен во время теста и порядка десятков мсек, что означает, что точность времени должна быть порядка +/- 100 мсек или около того. Немного грубая оценка? В любом случае это источник систематической ошибки mearure.

Кроме того, тесты проводились в режиме "Отладка" без оптимизации. В противном случае компилятор может изменить фактический тестовый код.

Итак, я получаю два результата: один для константы, помеченный как "(c)", и один для доступа с пометкой "(n)", а разница "dt" говорит мне, сколько времени занимает фактический доступ.

И вот результаты:

          Dictionary(c)/for: 1205ms (600000000)
          Dictionary(n)/for: 8046ms (589725196)
 dt = 6841

                List(c)/for: 1186ms (1189725196)
                List(n)/for: 2475ms (1779450392)
 dt = 1289

               Array(c)/for: 1019ms (600000000)
               Array(n)/for: 1266ms (589725196)
 dt = 247

 Dictionary[key](c)/foreach: 2738ms (600000000)
 Dictionary[key](n)/foreach: 10017ms (589725196)
 dt = 7279

            List(c)/foreach: 2480ms (600000000)
            List(n)/foreach: 2658ms (589725196)
 dt = 178

           Array(c)/foreach: 1300ms (600000000)
           Array(n)/foreach: 1592ms (589725196)
 dt = 292


 dt +/-.1 sec   for    foreach
 Dictionary     6.8       7.3
 List           1.3       0.2
 Array          0.2       0.3

 Same test, different system:
 dt +/- .1 sec  for    foreach
 Dictionary     14.4   12.0
       List      1.7    0.1
      Array      0.5    0.7

С лучшими оценками ошибок времени (как удалить системную ошибку измерения из-за временного сокращения?) можно сказать больше о результатах.

Похоже, что List/foreach имеет самый быстрый доступ, но накладные расходы убивают его.

Разница между List/for и List/foreach невелика. Может быть, задействован какой-то обман?

Кроме того, для доступа к массиву не имеет значения, если вы используете цикл for или цикл foreach. Результаты синхронизации и ее точность делают результаты "сравнимыми".

Использование словаря на сегодняшний день является самым медленным, я его рассматривал только потому, что с левой стороны (индексатор) у меня есть разреженный список целых чисел, а не диапазон, который используется в этих тестах.

Вот измененный тестовый код.

Dictionary<int, int> dict = new Dictionary<int, int>(6000000);
List<int> list = new List<int>(6000000);
Random rand = new Random(12345);
for (int i = 0; i < 6000000; i++)
{
    int n = rand.Next(5000);
    dict.Add(i, n);
    list.Add(n);
}
int[] arr = list.ToArray();

int chk = 0;
Stopwatch watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    int len = dict.Count;
    for (int i = 0; i < len; i++)
    {
        chk += 1; // dict[i];
    }
}
watch.Stop();
long c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("         Dictionary(c)/for: {0}ms ({1})", c_dt, chk);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    int len = dict.Count;
    for (int i = 0; i < len; i++)
    {
        chk += dict[i];
    }
}
watch.Stop();
long n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("         Dictionary(n)/for: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    int len = list.Count;
    for (int i = 0; i < len; i++)
    {
        chk += 1; // list[i];
    }
}
watch.Stop();
c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("               List(c)/for: {0}ms ({1})", c_dt, chk);

watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    int len = list.Count;
    for (int i = 0; i < len; i++)
    {
        chk += list[i];
    }
}
watch.Stop();
n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("               List(n)/for: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    for (int i = 0; i < arr.Length; i++)
    {
        chk += 1; // arr[i];
    }
}
watch.Stop();
c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("              Array(c)/for: {0}ms ({1})", c_dt, chk);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    for (int i = 0; i < arr.Length; i++)
    {
        chk += arr[i];
    }
}
watch.Stop();
n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("Array(n)/for: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in dict.Keys)
    {
        chk += 1; // dict[i]; ;
    }
}
watch.Stop();
c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("Dictionary[key](c)/foreach: {0}ms ({1})", c_dt, chk);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in dict.Keys)
    {
        chk += dict[i]; ;
    }
}
watch.Stop();
n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("Dictionary[key](n)/foreach: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in list)
    {
        chk += 1; // i;
    }
}
watch.Stop();
c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("           List(c)/foreach: {0}ms ({1})", c_dt, chk);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in list)
    {
        chk += i;
    }
}
watch.Stop();
n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("           List(n)/foreach: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in arr)
    {
        chk += 1; // i;
    }
}
watch.Stop();
c_dt = watch.ElapsedMilliseconds;
Console.WriteLine("          Array(c)/foreach: {0}ms ({1})", c_dt, chk);

chk = 0;
watch = Stopwatch.StartNew();
for (int rpt = 0; rpt < 100; rpt++)
{
    foreach (int i in arr)
    {
        chk += i;
    }
}
watch.Stop();
n_dt = watch.ElapsedMilliseconds;
Console.WriteLine("Array(n)/foreach: {0}ms ({1})", n_dt, chk);
Console.WriteLine("dt = {0}", n_dt - c_dt);

Ответ 13

В некоторых кратких тестах я нашел комбинацию из двух, чтобы быть лучше в том, что я бы назвал достаточно интенсивной математикой:

Тип: List<double[]>

Время: 00: 00: 05.1861300

Тип: List<List<double>>

Время: 00: 00: 05.7941351

Тип: double[rows * columns]

Время: 00: 00: 06.0547118

Запуск кода:

int rows = 10000;
int columns = 10000;

IMatrix Matrix = new IMatrix(rows, columns);

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();


for (int r = 0; r < Matrix.Rows; r++)
    for (int c = 0; c < Matrix.Columns; c++)
        Matrix[r, c] = Math.E;

for (int r = 0; r < Matrix.Rows; r++)
    for (int c = 0; c < Matrix.Columns; c++)
        Matrix[r, c] *= -Math.Log(Math.E);


stopwatch.Stop();
TimeSpan ts = stopwatch.Elapsed;

Console.WriteLine(ts.ToString());

Мне бы хотелось, чтобы у нас были некоторые классные аппаратные ускорители Matrix, такие как .NET Team, с классом System.Numerics.Vectors!

С# может быть лучшим языком ML с немного большей работой в этой области!