Как действительно Выстраивает. ForEach () выдерживают сравнение со стандартом для цикла в C#?

Я тоскую в течение дней, когда, как программист C, я мог ввести:

memset( byte_array, '0xFF' );

и заполните массив байтов символами 'FF'. Так, я искал замену для этого:

for (int i=0; i < byteArray.Length; i++)
{
    byteArray[i] = 0xFF;
}

В последнее время я использовал некоторые новые функции C# и использовал этот подход вместо этого:

Array.ForEach<byte>(byteArray, b => b = 0xFF);

Предоставленный, второй подход кажется инструментом для очистки и более симпатичен, но как производительность выдерживает сравнение с использованием первого подхода? Я представляю бесполезные издержки при помощи Linq и дженериков?

Спасибо, Dave

5
задан DaveN59 25 March 2010 в 19:01
поделиться

7 ответов

Array.ForEach<byte>(byteArray, b => b = 0xFF);

Это ничего не делает. Он устанавливает копию каждого байта в 0xFF, он никогда не устанавливается в массиве.

Чтобы сделать это проще, вы можете попробовать

Enumerable.Repeat((byte)0xFF, someCount).ToArray();

инициализировать массив

Repeat определенно будет медленнее, чем ваш цикл for. Согласно ссылке, опубликованной CAbbott в комментарии, это примерно на 10,5 секунд медленнее (12,38 против 1,7) для массива с более чем миллионом элементов, но это не большая разница, если вы делаете это всего несколько раз с небольшими массивы.

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

  public static T[] GetPreFilledArray<T>(T fillItem, int count)
  {
       var result = new T[count];
       for(int i =0; i < count; i++)
       {
           result[i] = fillItem;
       }
       return result;
  }

  byte[] byteArray = GetPreFilledArray((byte)0xFF, 1000);

Это должен быть довольно быстрый вариант, так как это в основном то, что вы сейчас делаете.

7
ответ дан 18 December 2019 в 14:44
поделиться

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

Что касается LINQ, я не уверен, какие эффекты он может иметь на производительность.

В конечном счете, инициализация - это такая второстепенная задача, что влияние на производительность не стоит вашего внимания.

0
ответ дан 18 December 2019 в 14:44
поделиться

Я обнаружил, что Array.ForEach значительно медленнее, чем цикл for или foreach, если они находятся на критическом пути выполнения. Однако, если вы не являетесь разработчиком фреймворка / библиотеки или вам действительно нужно инициализировать миллионы массивов, я бы вообще не беспокоился о производительности. Очень вероятно, что вы сможете получить гораздо больше, оптимизируя где-то еще.

0
ответ дан 18 December 2019 в 14:44
поделиться

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

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

Чтобы уточнить: вы вообще не используете LINQ. Метод ForEach - это метод в классе Array, предшествующий добавлению LINQ.

4
ответ дан 18 December 2019 в 14:44
поделиться

Если вам нужна производительность, как парень, который разместил вопрос, на который ссылался CAbott, вы можете посмотреть мой ответ, который я только что опубликовал .

1
ответ дан 18 December 2019 в 14:44
поделиться

Buffer.BlockCopy - это то, что я обычно использую, когда мне нужно поведение типа memset/memcpy. Я бы измерил производительность и использовал что-то вроде reflector. Возможно, внутри язык вызывает встроенные классы, которые в свою очередь являются тонкими обертками вокруг MEMCPY и MEMSET.

1
ответ дан 18 December 2019 в 14:44
поделиться

Если вы не делаете это во время очень критичной по производительности операции, у вас не будет проблем. Существует множество тестов, касающихся вызовов foreach и индексированной итерации, и разница минимальна.

Конечно, вы всегда можете протестировать его самостоятельно ...

0
ответ дан 18 December 2019 в 14:44
поделиться
Другие вопросы по тегам:

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