Я тоскую в течение дней, когда, как программист 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
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);
Это должен быть довольно быстрый вариант, так как это в основном то, что вы сейчас делаете.
Я не думаю, что универсальные шаблоны когда-либо могут ухудшить производительность. Они в первую очередь обрабатываются во время компиляции, и их общая цель - устранить необходимость приведения типов между объектом и желаемым типом, что в худшем случае будет иметь незначительный эффект, а в лучшем случае приведет к измеримому увеличению производительности.
Что касается LINQ, я не уверен, какие эффекты он может иметь на производительность.
В конечном счете, инициализация - это такая второстепенная задача, что влияние на производительность не стоит вашего внимания.
Я обнаружил, что Array.ForEach значительно медленнее, чем цикл for или foreach, если они находятся на критическом пути выполнения. Однако, если вы не являетесь разработчиком фреймворка / библиотеки или вам действительно нужно инициализировать миллионы массивов, я бы вообще не беспокоился о производительности. Очень вероятно, что вы сможете получить гораздо больше, оптимизируя где-то еще.
Второй метод использует делегат для установки каждого байта, это означает, что есть вызов метода для каждого байта в массиве. Это слишком много накладных расходов, чтобы просто установить байт.
Простой цикл, с другой стороны, довольно хорошо оптимизируется компилятором. Он определит, что индекс не может находиться за пределами массива, поэтому он пропустит проверку границ.
Чтобы уточнить: вы вообще не используете LINQ. Метод ForEach - это метод в классе Array, предшествующий добавлению LINQ.
Если вам нужна производительность, как парень, который разместил вопрос, на который ссылался CAbott, вы можете посмотреть мой ответ, который я только что опубликовал .
Buffer.BlockCopy - это то, что я обычно использую, когда мне нужно поведение типа memset/memcpy. Я бы измерил производительность и использовал что-то вроде reflector. Возможно, внутри язык вызывает встроенные классы, которые в свою очередь являются тонкими обертками вокруг MEMCPY и MEMSET.
Если вы не делаете это во время очень критичной по производительности операции, у вас не будет проблем. Существует множество тестов, касающихся вызовов foreach и индексированной итерации, и разница минимальна.
Конечно, вы всегда можете протестировать его самостоятельно ...