如何快速将数组归零?

Posted

技术标签:

【中文标题】如何快速将数组归零?【英文标题】:How to quickly zero out an array? 【发布时间】:2010-11-27 07:42:34 【问题描述】:

我目前在 for 循环中执行此操作,并且我知道在 C 中有 ZeroMemory API,但在 C# 中似乎不可用。 Java 中的某种等效的 Array.fill 也不存在。我只是想知道是否有更简单/更快的方法?

【问题讨论】:

初始化时不需要清除。您的帖子没有说明这是在初始化期间还是在您将数据放入数组之后。 在我将数据放入数组之后。 Dustin:我认为只是告诉我谷歌搜索会起作用是相当粗鲁的。显然,我的想法与您的不同,通过“c# 中的零内存”查看并没有让我产生 Array.Clear() 【参考方案1】:

试试Array.Clear():

设置数组中元素的范围 为零,false,或 null (Visual Basic 中没有),取决于 关于元素类型。

【讨论】:

【参考方案2】:

C++:memset(array, 0, array_length_in_bytes);

C++11:array.fill(0);

C#:Array.Clear(array, startingIndex, length);

Java:Arrays.fill(array, value);

【讨论】:

我反对 C++ 中的 c 函数 memset 支持 C++ std::fill。通常在优化代码中的memset 成为对库memset 的调用,而std::fill 只是一些汇编指令,根本不需要调用。【参考方案3】:

更新

根据benchmark 对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();

【讨论】:

【参考方案4】:
Array.Clear(integerArray, 0, integerArray.Length);

【讨论】:

【参考方案5】:

有几个人发布了答案,然后将其删除,并表示在任何语言中,for 循环的性能都与 memset 或 FillMemory 或其他类似。

例如,编译器可能会将其分块为 64 位对齐的片段,以利用 64 位零赋值指令(如果可用)。它将考虑对齐和东西。 Memset 的实现肯定不简单。

一个memset.asm。另见memset-is-faster-than-simple-loop.html

永远不要低估编译器和标准库编写者的无限狡猾。

【讨论】:

我用我的 for 循环与 Array.Clear() 进行了测试。 Array.Clear() 在一个 4K 数组的循环中执行 200 万次耗时 620 毫秒。 for 循环耗时 13030 毫秒。 @esac 虽然这肯定回答了您的问题,但对于所有操作系统和硬件是否仍然如此,这仍然是一个悬而未决的问题。我同意 Array.Clear() 将至少与 for 循环一样快,并且可能更快,这使得 Array.Clear() 成为显而易见的选择。 (另外,它更易于阅读。)【参考方案6】:

使用 dll import 调用方法。它快速且易于使用:)

 [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);

这只会将给定的数组设置为零

【讨论】:

【参考方案7】:

我相信这就是你要找的东西,我是用 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

【讨论】:

以上是关于如何快速将数组归零?的主要内容,如果未能解决你的问题,请参考以下文章

在C代码中将数组归零[重复]

将数组中的低值归零的最快方法?

在 C 中将二维数组归零的最快方法是啥?

如何在 python 中使用掩码将特定元素归零?

在 Linux 上是不是将 boost 内存映射文件归零

C++ OpenCV 中的快速索引