【问题标题】:Fastest way to fill an array with a single value [duplicate]用单个值填充数组的最快方法[重复]
【发布时间】:2011-08-22 01:54:03
【问题描述】:

我想用我拥有的单个值填充 2D 数组,但是,我想以最快的方式做到这一点,2D 数组的总长度将超过 200k+,随着时间的推移将超过 200这些数组。我研究了 Buffer.BlockCopy 和 Array.Copy,但是,它们都将数组作为源/目标,其中我唯一拥有的数组是目标,源是单个值。

在源是单个值而不是数组的情况下填充数组的最快方法是什么?

【问题讨论】:

  • 有几种不同的方法,这家伙列出了一些更常见的方法——他甚至还好心地对其进行了基准测试:dotnetperls.com/initialize-array 在内存中保存 200K 项,甚至如果它们是原始的,将会占用大量内存 - 你在做什么,你需要所有 200K 的项目,并且需要恒定的时间访问(每个项目)?
  • 可能不是一个重复的问题,他没有说他想用它初始化数组,也可以意味着用 valeu 填充大部分数组

标签: c# algorithm performance optimization memory


【解决方案1】:

我发现最快的方法是使用 Array.Copy,每次循环时复制大小加倍。无论是用单个值填充数组还是用值数组填充,速度基本相同。

在我对 20,000,000 个数组项的测试中,此函数的速度是 for 循环的两倍。

using System;

namespace Extensions
{
    public static class ArrayExtensions
    {
        public static void Fill<T>(this T[] destinationArray, params T[] value)
        {
            if (destinationArray == null)
            {
                throw new ArgumentNullException("destinationArray");
            }

            if (value.Length >= destinationArray.Length)
            {
                throw new ArgumentException("Length of value array must be less than length of destination");
            }

            // set the initial array value
            Array.Copy(value, destinationArray, value.Length);

            int arrayToFillHalfLength = destinationArray.Length / 2;
            int copyLength;

            for(copyLength = value.Length; copyLength < arrayToFillHalfLength; copyLength <<= 1)
            {
                Array.Copy(destinationArray, 0, destinationArray, copyLength, copyLength);
            }

            Array.Copy(destinationArray, 0, destinationArray, copyLength, destinationArray.Length - copyLength);
        }
    }
}

我在 https://secureapplicationlifestyle.com/2011/11/initialize-array-to-value-in-c-very.htmlhttps://secureapplicationlifestyle.com/2014/04/better-array-fill-function.html 上写了这篇博客

【讨论】:

  • 我需要填充一个 [,] 数组,所以我复制了您的 Fill 扩展名并将签名更改为 public static void Fill&lt;T&gt;(this T[,] destinationArray, T[,] value) 并像这样调用它:myLargeArray.Fill(new [,] { { double.NaN }, { double.NaN }});,它工作得很好。谢谢!
【解决方案2】:

有关一些相关信息,请参阅What is the equivalent of memset in C#?

正如那个问题中提到的(非常接近这个问题的欺骗),除非您想进入 unmanaged code,否则 for 循环通常是最好的。

所以这应该很快:

int[] arr = new int[MAX_ELEMENTS];
for (int i = 0; i < arr.Length; ++i)
{
    array[i] = MY_VALUE;
}

与所有与性能相关的事情一样,让某些事情发挥作用,然后衡量瓶颈是什么。强调“量”。试图猜测瓶颈是什么通常是个坏主意(:

【讨论】:

    【解决方案3】:

    Array.Copy 可能比 for 循环更优化,所以使用它。

    void FillArray<T>(T[] arr, T fillValue)
    {
        int i = 0;
        if (arr.Length > 16) {
        {
            do {
                array[i++] = fillValue;
            } while (i < arr.Length)
            while (i + 16 < arr.Length) {
                Array.Copy(arr, 0, arr, i, 16);
                i = i + 16;
            }
        }
        while (i < arr.Length)
        {
            array[i++] = fillValue;
        }
    }
    

    (我很想看看这个和朴素的 for 循环之间的性能比较,对于不同的类型和数组大小)

    【讨论】:

      猜你喜欢
      • 2013-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-06
      • 2018-08-04
      • 1970-01-01
      • 1970-01-01
      • 2017-06-11
      相关资源
      最近更新 更多