2015-06-22 3 views
4

Для сериализации примитивного массива я задаюсь вопросом, как преобразовать примитив [] в его соответствующий байт []. (т. е. int [128] в байт [512] или пользовательский указатель [] в байт [] ...) Назначением может быть поток памяти, сетевое сообщение, файл, что угодно. Целью является производительность (Сериализация & Время десериализации), чтобы иметь возможность писать с некоторыми потоками байт [] за один кадр, а не зацикливать все значения или выделять с помощью некоторого конвертера.Как преобразовать примитивный [] в байт []

Некоторые уже раствор исследовали:

Regular Loop для записи/чтения

//array = any int[]; 
myStreamWriter.WriteInt32(array.Length); 
for(int i = 0; i < array.Length; ++i) 
    myStreamWriter.WriteInt32(array[i]); 

Это решение работает для сериализации и десериализации И, как в 100 раз быстрее, чем при использовании стандартной System.Runtime.Serialization в сочетании с BinaryFormater для сериализации/десериализации одного int или нескольких из них.

Но это решение становится медленнее, если array.Length содержит более 200/300 значений (для Int32).

В ролях:

Кажется, что C# не может напрямую преобразовать Int [] в байт [] или bool [] в байт [].

BitConverter.Getbytes()

Это решение работает, но он выделяет новые байты [] при каждом вызове цикла через мой междунар []. Спектакли, конечно, ужасно

Marshal.Copy

Да, это решение тоже работает, но та же проблема, как и предыдущие BitConverter один.

C++ взломать

Поскольку прямой бросок не допускается в C#, я судимые некоторые C++ взломать после просмотра в память, что длина массива хранится 4 байта перед началом

ARRAYCAST_API void Cast(int* input, unsigned char** output) 
{ 
    // get the address of the input (this is a pointer to the data) 
    int* count = input; 
    // the size of the buffer is located just before the data (4 bytes before as this is an int) 
    count--; 
    // multiply the number of elements by 4 as an int is 4 bytes 
    *count = *count * 4; 
    // set the address of the byte array 
    *output = (unsigned char*)(input); 
} 

и данных массива C#, который называют:

byte[] arrayB = null; 
int[] arrayI = new int[128]; 
for (int i = 0; i < 128; ++i) 
    arrayI[i] = i; 

// delegate call 
fptr(arrayI, out arrayB); 

Я успешно восстановить свою ИНТ [128] в C++, переключите длину массива, и затрагивающий т он имеет правый адрес в моем «output» var, но C# только возвращает байт [1] в качестве возврата. Кажется, что я не могу так легко взломать управляемую переменную.

Итак, я действительно начинаю думать, что все тезисы, которые я хочу достичь, просто невозможны в C# (int [] -> byte [], bool [] -> byte [], double [] -> byte [] ...) без распределения/копирования ...

Что мне не хватает?

+0

Можете ли вы уточнить, что вы пытаетесь сделать? Вы сериализуете массивы? Сериализовать где? HDD может стать вашим настоящим узким местом. И, возможно, вам следует использовать 'byte []' для хранения ваших исходных данных (не нужно сериализовывать то, но получение данных сложно). – Sinatr

+0

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

+0

Одна заметка на «C++ hack». Я хочу отметить, что вы можете делать возиться с указателями и тэгами в C#, если хотите. Я не делал этого сам, но https://msdn.microsoft.com/en-us/library/f58wzh21(VS.80).aspx может быть отправной точкой, если вы хотите посмотреть на него. Я столкнулся с этим в контексте быстрой обработки растровых данных на изображениях, но при условии, что это также просто манипулирует массивами, это может сработать для вас, если вам действительно нужна производительность. – Chris

ответ

4

Как насчет использования Buffer.BlockCopy?

// serialize 
var intArray = new[] { 1, 2, 3, 4, 5, 6, 7, 8 }; 
var byteArray = new byte[intArray.Length * 4]; 
Buffer.BlockCopy(intArray, 0, byteArray, 0, byteArray.Length); 

// deserialize and test 
var intArray2 = new int[byteArray.Length/4]; 
Buffer.BlockCopy(byteArray, 0, intArray2, 0, byteArray.Length); 
Console.WriteLine(intArray.SequenceEqual(intArray2)); // true 

Обратите внимание, что BlockCopy по-прежнему выделения/копирования за кулисами.Я уверен, что это неизбежно в управляемом коде, а BlockCopy, вероятно, так же хорош, как и для этого.

+0

Работает ли 'BlockCopy' для примитивных массивов valuetype? (Я подозреваю, так) – leppie

+0

Это может быть хорошим способом. я попробую это сегодня, с каким-то статическим заблокированным байтом [] буфером, чтобы избежать множественных распределений и оставаться потокобезопасным. Спасибо за идею – jlevet

+0

Я использую этот метод, за исключением десятичного типа. – jlevet

Смежные вопросы