我目前正在使用for循环进行操作,在C语言中有ZeroMemory API,但是似乎在C#中并不可用。同样,Java中的Array.fill也没有相应的方法。我想知道是否有更简单/更快的方法?
我目前正在使用for循环进行操作,在C语言中有ZeroMemory API,但是似乎在C#中并不可用。同样,Java中的Array.fill也没有相应的方法。我想知道是否有更简单/更快的方法?
尝试使用 Array.Clear() 方法:
该方法会将数组中指定范围内的元素设置为零、false 或 null(在 Visual Basic 中为 Nothing),具体取决于元素类型。
'\0'
。 - JoggeC++: memset(array, 0, array_length_in_bytes);
C++11: array.fill(0);
C#: Array.Clear(array, startingIndex, length);
Java: Arrays.fill(array, value);
memset
函数,通过将数组元素全部置为0来完成初始化;而C++11则提供了更加方便且易读的语法array.fill(0)
。在C#中,可以使用Array.Clear
方法来清空数组中指定范围内的元素;而在Java中,则可使用Arrays.fill
方法来将指定数组中的所有元素均赋值为指定值。std::fill
而不是C函数memset
。在优化代码中,memset
通常会变成对库memset
的调用,而std::fill
只需要几个汇编指令,根本不需要调用。 - Hi-Angel更新
根据关于Array.Clear()
和array[x] = default(T)
性能的基准测试,我们可以得出以下两种情况需要考虑:
A) 数组长度为1到76个项;
B) 数组长度大于等于77个项。
因此,图中的橙色线条代表了Array.Clear()
方法。
图中的蓝色线条代表了array[x] = default(T)
方法(迭代数组并将其值设置为default(T)
)。
您可以编写一个Helper来完成此任务,例如:
public static class ArrayHelper
{
// Performance-oriented algorithm selection
public static void SelfSetToDefaults<T>(this T[] sourceArray)
{
if (sourceArray.Length <= 76)
{
for (int i = 0; i < sourceArray.Length; i++)
{
sourceArray[i] = default(T);
}
}
else { // 77+
Array.Clear(
array: sourceArray,
index: 0,
length: sourceArray.Length);
}
}
}
使用方法:
someArray.SelfSetToDefaults();
备注:
这个测试是针对 .NET Framework 4.x 进行的。
编辑(.NET6):
根据 Dai 的评论,在 .NET6 中,Array.Clear()
命令在 N > ~25 时现在更快了。
N > ~75
ж—¶пјҢArray.Clear()
жӣҙеҝ«пјҢдҪҶеңЁ.NET 6дёӯпјҢжҲ‘еҸ‘зҺ°N > ~25
ж—¶пјҢArray.Clear()
зҺ°еңЁжӣҙеҝ«гҖӮ - DaiArray.Clear(integerArray, 0, integerArray.Length);
有几个人发布了答案,然后删除了它们,说无论用什么语言,for循环与memset或FillMemory等方法在性能上是相同的。
例如,编译器可能将其划分为64位对齐的块,以利用64位零赋值指令(如果有的话)。它将考虑对齐和其他因素。Memset的实现肯定不是简单的。
参见 memset.asm和memset-is-faster-than-simple-loop.html 来查看示例。
永远不要低估编译器和标准库作者的巧妙程度。
1 <= N < ~25-75
),Array.Clear()
比 for
循环慢,这是因为 Array.Clear()
内部逻辑需要进行参数验证和获取数组的维度/边界。 - Dai [DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern IntPtr MemSet(IntPtr dest, int c, int byteCount);
c是您想在内存中设置的值。
或者
[DllImport("kernel32.dll", EntryPoint="RtlZeroMemory")]
public unsafe static extern bool ZeroMemory(byte* destination, int length);
这仅将给定的数组设置为零。
我相信这就是你要找的,我用Visual Basic写的,但我相信你可以转换它。
Imports System.Runtime.InteropServices
Module Module1
'import Kernel32 so we can use the ZeroMemory Windows API function
<DllImport("kernel32.dll")>
Public Sub ZeroMemory(ByVal addr As IntPtr, ByVal size As IntPtr)
End Sub
Private Sub ZeroArray(array As ArrayList)
'Iterate from 0 to the lenght of the array zeroing each item at that index
For i As Integer = 0 To array.Count - 1
'Pin the array item in memory
Dim gch As GCHandle = GCHandle.Alloc((array(i)), GCHandleType.Pinned)
'Get the memory address of the object pinned
Dim arrayAddress As IntPtr = gch.AddrOfPinnedObject()
'Get size of the array
Dim arraySize As IntPtr = CType(array.Count, IntPtr)
'Zero memory at the current index address in memory
ZeroMemory(arrayAddress, arraySize)
gch.Free()
Next
End Sub
Sub Main()
'Initialize ArrayList with items
Dim strArray As New ArrayList From {
"example one",
"example two",
"example three"
}
'Pass array as parameter to a function which will iterate through the arraylist zeroing each item in memory
ZeroArray(strArray)
Console.ReadLine()
End Sub
End Module