Todas las respuestas solo escriben bytes individuales. ¿Qué ocurre si desea rellenar una matriz de bytes con palabras? ¿O flota? Encuentro uso para eso de vez en cuando. Así que después de haber escrito un código similar a 'memset' de forma no genérica varias veces y al llegar a esta página para encontrar un buen código para bytes individuales, escribí el método a continuación.
Creo que PInvoke y C++/CLI tienen sus inconvenientes. ¿Y por qué no tener el tiempo de ejecución 'PInvoke' para usted en mscorxxx? Array.Copy y Buffer.BlockCopy son ciertamente código nativo. BlockCopy ni siquiera es 'seguro': puede copiar una mitad larga sobre otra, o sobre un DateTime, siempre y cuando estén en matrices.
Al menos no iría a presentar un nuevo proyecto de C++ para cosas como esta: es casi una pérdida de tiempo.
Así que aquí está básicamente una versión extendida de las soluciones presentadas por Lucero y TowerOfBricks que se pueden usar para memset longs, ints, etc. así como para bytes individuales.
public static class MemsetExtensions
{
static void MemsetPrivate(this byte[] buffer, byte[] value, int offset, int length) {
var shift = 0;
for (; shift < 32; shift++)
if (value.Length == 1 << shift)
break;
if (shift == 32 || value.Length != 1 << shift)
throw new ArgumentException(
"The source array must have a length that is a power of two and be shorter than 4GB.", "value");
int remainder;
int count = Math.DivRem(length, value.Length, out remainder);
var si = 0;
var di = offset;
int cx;
if (count < 1)
cx = remainder;
else
cx = value.Length;
Buffer.BlockCopy(value, si, buffer, di, cx);
if (cx == remainder)
return;
var cachetrash = Math.Max(12, shift); // 1 << 12 == 4096
si = di;
di += cx;
var dx = offset + length;
// doubling up to 1 << cachetrash bytes i.e. 2^12 or value.Length whichever is larger
for (var al = shift; al <= cachetrash && di + (cx = 1 << al) < dx; al++) {
Buffer.BlockCopy(buffer, si, buffer, di, cx);
di += cx;
}
// cx bytes as long as it fits
for (; di + cx <= dx; di += cx)
Buffer.BlockCopy(buffer, si, buffer, di, cx);
// tail part if less than cx bytes
if (di < dx)
Buffer.BlockCopy(buffer, si, buffer, di, dx - di);
}
}
Teniendo esto simplemente puede añadir métodos cortos para tomar el tipo de valor que necesita para Memset con y llamar al método privado, por ejemplo,acaba de encontrar reemplazar ulong en este método:
public static void Memset(this byte[] buffer, ulong value, int offset, int count) {
var sourceArray = BitConverter.GetBytes(value);
MemsetPrivate(buffer, sourceArray, offset, sizeof(ulong) * count);
}
O ir tonta y hacerlo con cualquier tipo de estructura (aunque el MemsetPrivate anterior sólo funciona para estructuras que el Mariscal a un tamaño que es una potencia de dos):
public static void Memset<T>(this byte[] buffer, T value, int offset, int count) where T : struct {
var size = Marshal.SizeOf<T>();
var ptr = Marshal.AllocHGlobal(size);
var sourceArray = new byte[size];
try {
Marshal.StructureToPtr<T>(value, ptr, false);
Marshal.Copy(ptr, sourceArray, 0, size);
} finally {
Marshal.FreeHGlobal(ptr);
}
MemsetPrivate(buffer, sourceArray, offset, count * size);
}
He cambiado el initblk mencionado anteriormente para tomar ulongs para comparar el rendimiento con mi código y que silenciosamente falla - el código se ejecuta pero el búfer resultante contiene el byte menos significativo del ulong solamente.
Sin embargo, comparé la escritura de rendimiento como un gran buffer con for, initblk y mi método memset. Los tiempos son en total un total de más de 100 repeticiones escribiendo 8 bytes ulios, cualquiera que sea la cantidad de veces que se ajuste a la longitud del búfer. La versión for es desenrollada manualmente en bucle para los 8 bytes de un solo ulong.
Buffer Len #repeat For millisec Initblk millisec Memset millisec
0x00000008 100 For 0,0032 Initblk 0,0107 Memset 0,0052
0x00000010 100 For 0,0037 Initblk 0,0102 Memset 0,0039
0x00000020 100 For 0,0032 Initblk 0,0106 Memset 0,0050
0x00000040 100 For 0,0053 Initblk 0,0121 Memset 0,0106
0x00000080 100 For 0,0097 Initblk 0,0121 Memset 0,0091
0x00000100 100 For 0,0179 Initblk 0,0122 Memset 0,0102
0x00000200 100 For 0,0384 Initblk 0,Memset 0,0126
0x00000400 100 For 0,0789 Initblk 0,0130 Memset 0,0189
0x00000800 100 For 0,1357 Initblk 0,0153 Memset 0,0170
0x00001000 100 For 0,2811 Initblk 0,0167 Memset 0,0221
0x00002000 100 For 0,5519 Initblk 0,0278 Memset 0,0274
0x00004000 100 For 1,1100 Initblk 0,0329 Memset 0,0383
0x00008000 100 For 2,2332 Initblk 0,0827 Memset 0,0864
0x00010000 100 For 4,4407 Initblk 0,1551 Memset 0,1602
0x00020000 100 For 9,1331 Initblk 0,2768 Memset 0,3044
0x00040000 100 For 18,2497 Initblk 0,5500 Memset 0,5901
0x00080000 100 For 35,8650 Initblk 1,1236 Memset 1,5762
0x00100000 100 For 71,6806 Initblk 2,2836 Memset 3,2323
0x00200000 100 For 77,8086 Initblk 2,1991 Memset 3,0144
0x00400000 100 For 131,2923 Initblk 4,7837 Memset 6,8505
0x00800000 100 For 263,2917 Initblk 16,1354 Memset 33,3719
Excluí la primera llamada cada vez, ya que ambos initblk y memset toman un golpe de Creo que estaba a punto .22ms para la primera convocatoria. Ligeramente sorprendente, mi código es más rápido para llenar búferes cortos que initblk, ya que tiene media página llena de código de configuración.
Si alguien tiene ganas de optimizar esto, adelante realmente. Es posible.
Tenga en cuenta que para los bytes, la respuesta de Mark necesita una ligera modificación. byte [] image = Enumerable.Repeat ((byte) 255, [....]). ToArray(); De lo contrario, supondrá que desea int [] devuelto. – Jedidja
Si tiene que ir por la ruta de rendimiento sospecho que usa inseguro/fijo y establece Int32 o Int64 a la vez y mover el puntero sería lo más rápido que puede lograr en C# (y usar un byte para los bytes restantes). –
Buenos puntos sobre probar el rendimiento. Definitivamente lo haré :) – Jedidja