所有的答案都只寫單字節 - 如果你想用字填充字節數組怎麼辦?還是漂浮?我現在覺得它很有用。因此,在用非泛型方式將類似代碼寫入'memset'幾次併到達此頁面以找到單字節的良好代碼之後,我開始着手編寫下面的方法。
我認爲PInvoke和C++/CLI各有缺點。爲什麼不把你的運行時'PInvoke'換成mscorxxx? Array.Copy和Buffer.BlockCopy肯定是本地代碼。 BlockCopy甚至不是'安全的' - 只要它們在數組中,您可以在另一個上覆制一段時間,或者在DateTime上覆制一段時間。
至少我不會爲這樣的東西去新的C++項目 - 這幾乎可以肯定是浪費時間。
因此,這裏基本上是由Lucero和TowerOfBricks提供的解決方案的擴展版本,可用於memset longs,ints等以及單個字節。
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);
}
}
有了這個,你可以簡單地添加短的方法來把你需要與memset的並調用私有方法,例如值類型只要找到替代ULONG在這個方法:
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);
}
或者去愚蠢的,與任何類型結構的做到這一點(雖然只有上述MemsetPrivate工程結構元帥的大小爲二的冪):
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);
}
我改變了之前提到的initblk,以便使用ulong來比較性能和我的代碼,並且靜靜地失敗 - 代碼運行但結果緩衝區僅包含ulong的最低有效字節。然而,我比較寫作緩衝區大小爲,initblk和我的memset方法的性能。時間以ms爲單位,總共超過100次重複,寫入8個字節的長度,無論多少次都適合緩衝區長度。對於單個ulong的8個字節,for版本是手動循環展開的。
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
我排除在外,每次第一個呼叫,因爲這兩個initblk和memset採取一擊的,我相信它是關於.22ms的第一個電話。稍微令人驚訝的是,我的代碼比initblk填充短緩衝區更快,看到它有半頁的完整安裝代碼。
如果有人覺得這樣優化,那就真的吧。這是可能的。
請注意,對於字節,Mark的答案需要稍作修改。 byte [] image = Enumerable.Repeat((byte)255,[....])。ToArray(); 否則它會假定你想要返回int []。 – Jedidja 2009-12-13 20:12:56
如果你必須走性能路線,我懷疑使用unsafe/fixed並且一次設置一個Int32或Int64,並且移動指針會是你在c#中可以達到的最快速度(並且對於左邊的字節使用一個字節)。 – 2009-12-13 21:07:46
測試性能的好處。肯定會這麼做:) – Jedidja 2009-12-13 21:13:07