Каждый раз, когда я говорю управляемый по сравнению с неуправляемой производительностью, мне нравится указывать на ряд на Rico (и Raymond) сделал сравнение C++ и версий C# китайского/Английского словаря. Этот поиск Google позволит Вам читать для себя, но мне нравится сводка Rico.
Так я стыдящийся моим сокрушительным поражением? Едва. Управляемый код получил очень хороший результат для едва любого усилия. Побеждать управляемого Raymond имело к:
- Запись его собственный материал файлового ввода-вывода
- Запись его собственная Запись строкового класса
- его собственное средство выделения
- Запись его собственное международное отображение
, Конечно, он пользовался доступными более низкими библиотеками уровня, чтобы сделать это, но это - все еще большая работа. Можно ли назвать то, что оставило программу STL? Я не думаю так, я думаю, что он сохранил станд.:: векторный класс, который в конечном счете никогда не был проблемой и он сохранил функцию находки. В значительной степени всего остального не стало.
Так, да, можно определенно победить CLR. Raymond может заставить свою программу пойти еще быстрее, я думаю.
Интересно, время для парсинга файла, как сообщается обеими программами внутренние таймеры о том же - 30 мс для каждого. Различие находится в издержках.
Для меня нижняя строка - то, что потребовалось 6 изменений для неуправляемой версии для избиения управляемой версии, которая была простым портом исходного неуправляемого кода. Если Вы нуждаетесь в каждом последнем бите производительности (и имеете время и экспертные знания для получения его), необходимо будет пойти неуправляемые, но для меня, я воспользуюсь преимуществом порядка величины, которое я имею на первых версиях по 33%, которые я получаю, если я пробую 6 раз.
BitConverter
, вполне возможно, ваш друг.
Однако он обычно возвращает вам новый байтовый массив. Он также не позволяет указывать порядок байтов. У меня есть класс EndianBitConverter
в MiscUtil , в котором есть методы для преобразования примитивных типов путем копирования данных непосредственно в существующий массив байтов.
Например:
// Copy the bytes from the integer "value" into a byte array
// (buffer) starting at index 5
EndianBitConverter.Little.CopyBytes(value, buffer, 5);
Сделайте это так, как это делает BinaryWriter:
buffer[0] = (byte) value;
buffer[1] = (byte) (value >> 8);
buffer[2] = (byte) (value >> 0x10);
buffer[3] = (byte) (value >> 0x18);
(очевидно, это скопирует int в первые 4 байта массива)
Есть много разных способов сделать это, но чтобы было удобнее, давайте воспользуемся новой функцией c #: extensions.
Целое число из 32-битного диапазона занимает 4 байта, поэтому оно будет занимать 4 места в байте []. Как разбить целое число на 4 составляющих байта? Вы можете сделать это с помощью оператора битовой манипуляции >>. Этот оператор сдвигает биты целого числа на указанное количество бит. Например:
integer = 10399
binary = 00101000 10011111
10399 >> 1 == 0010100 01001111 each bit shifted by 1
Поскольку байт равен 8 битам, если мы сдвинем целое число на 8 бит, мы получим новое значение второго байта целого числа в самой правой позиции битов
10399 >> 8 = 00000000 00101000
Обратите внимание, что второй байт не является первым байт, а остальные биты были заменены на 0.
Мы можем использовать этот трюк, чтобы переместить байты в первую позицию, а затем принудительно выполнить приведение к байту, которое отбросит 3 других байта и оставит нам последний значение в байтах:
(byte)(10399 >> 8) == 0010100
Таким образом, использование этой техники для 4 байтов даст нам доступ к каждому из них, и мы скопируем их в целевой массив, который был передан нашему новому методу CopyToByteArray:
public static class Int32Extension
{
public static void CopyToByteArray(this int source, byte[] destination, int offset)
{
if (destination == null)
throw new ArgumentException("Destination array cannot be null");
// check if there is enough space for all the 4 bytes we will copy
if (destination.Length < offset + 4)
throw new ArgumentException("Not enough room in the destination array");
destination[offset] = (byte)(source >> 24); // fourth byte
destination[offset+1] = (byte)(source >> 16); // third byte
destination[offset+2] = (byte)(source >> 8 ); // second byte
destination[offset+3] = (byte)source; // last byte is already in proper position
}
}
Обратите внимание, что мы могли скопировать байты в обратном порядке. порядок, который зависит от вашей реализации.
Функция расширения позволит вам получить доступ к новой функции как к члену целочисленного класса:
int something = 20;
byte[] array = new byte[4];
something.CopyToByteArray(array,0);
byte[] bytes = new byte[listOfInts.Count * sizeof(int)];
int pos = 0;
foreach(int i in listOfInts)
{
byte[] b = BitConverter.GetBytes(i);
b.CopyTo(bytes, pos);
pos += b.Length;
}
Buffer.BlockCopy (intArray, 0, byteArray, 0, 4 * intArray.Length)
Копирует данные между двумя массивами. Последний аргумент - это количество копируемых данных в байтах.