【问题标题】: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()

标签: c# arrays memory


【解决方案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】:

    更新

    根据benchmarkArray.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
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-03-23
            • 1970-01-01
            • 2023-04-04
            • 2016-08-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多