example - cast en c#
Fundición rápida en C#con BitConverter, ¿puede ser más rápido? (4)
En nuestra aplicación, tenemos una matriz de bytes muy grande y tenemos que convertir estos bytes en diferentes tipos. Actualmente, usamos BitConverter.ToXXXX()
para este propósito. Nuestros grandes bateadores son, ToInt16
y ToUInt64
.
Para UInt64
, nuestro problema es que la secuencia de datos tiene realmente 6 bytes de datos para representar un entero grande. Como no hay una función nativa para convertir 6 bytes de datos a UInt64
, hacemos:
UInt64 value = BitConverter.ToUInt64() & 0x0000ffffffffffff;
Nuestro uso de ToInt16
es más simple, no es necesario hacer ninguna manipulación de bits.
Hacemos tantas de estas 2 operaciones que quería preguntarle a la comunidad SO si hay una forma más rápida de hacer estas conversiones. En este momento, estas dos funciones consumen aproximadamente el 20% de nuestros ciclos completos de CPU.
¿Has pensado en usar punteros de memoria directamente? No puedo responder por su rendimiento, pero es un truco común en C ++ / C ...
byte[] arr = { 1, 2, 3, 4, 5, 6, 7, 8 ,9,10,11,12,13,14,15,16};
fixed (byte* a2rr = &arr[0])
{
UInt64* uint64ptr = (UInt64*) a2rr;
Console.WriteLine("The value is {0:X2}", (*uint64ptr & 0x0000FFFFFFFFFFFF));
uint64ptr = (UInt64*) ((byte*) uint64ptr+6);
Console.WriteLine("The value is {0:X2}", (*uint64ptr & 0x0000FFFFFFFFFFFF));
}
Necesitarás hacer que tu montaje sea "inseguro" en la configuración de compilación, así como también marcar el método en el que harías esto inseguro. También estás vinculado al pequeño endian con este enfoque.
Por qué no:
UInt16 valLow = BitConverter.ToUInt16();
UInt64 valHigh = (UInt64)BitConverter.ToUInt32();
UInt64 Value = (valHigh << 16) | valLow;
Puede hacer que sea una sola declaración, aunque el compilador JIT probablemente lo haga automáticamente.
Eso evitará que leas esos dos bytes adicionales que terminas tirando.
Si eso no reduce la CPU, entonces probablemente quiera escribir su propio convertidor que lea los bytes directamente desde el búfer. Puede usar indexación de matriz o, si lo considera necesario, código inseguro con punteros.
Tenga en cuenta que, como señaló un comentarista, si utiliza alguna de estas sugerencias, o está limitado a un "endian-ness" particular, o tendrá que escribir su código para detectar little / big endian y reaccionar en consecuencia . La muestra de código que mostré arriba funciona para little endian (x86).
Puede usar la clase System.Buffer
para copiar una matriz completa a otra matriz de un tipo diferente como una operación rápida de "copia en bloque" :
El método BlockCopy accede a los bytes en la matriz de parámetros src utilizando compensaciones en la memoria, no en la programación de construcciones como índices o límites de matriz superior e inferior.
Los tipos de matriz deben ser de tipo "primitivo", deben alinearse y la operación de copia es sensible a endian. En su caso de enteros de 6 bytes, no puede alinearse con ninguno de los tipos ''primitivos'' de .NET, a menos que pueda obtener la matriz de origen con dos bytes de relleno para cada seis, que luego se alineará con Int64
. Pero este método funcionará para las matrices de Int16
, lo que puede acelerar algunas de sus operaciones.
Vea mi respuesta para una pregunta similar aquí . Es la misma manipulación insegura de la memoria que en la respuesta de Jimmy, pero de una manera más "amistosa" para los consumidores. Te permitirá ver tu matriz de byte
como UInt64
matriz UInt64
.