【问题标题】:how to initialize array to -1 fast? [duplicate]如何快速将数组初始化为-1? [复制]
【发布时间】:2012-05-26 15:02:10
【问题描述】:

我知道我不应该优化程序的每一个点,让我们假设我必须优化数组初始化。

所以我编写了比较 for loopArray.Clear 的程序

using System;
using System.Diagnostics;

namespace TestArraysClear
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] a = new int[100000];
            Stopwatch sw = Stopwatch.StartNew();
            for (int i = 0; i < 10; i++)
            {
                sw.Reset(); 
                sw.Start();
                for (int j = 0; j < a.Length; j++)
                {
                    a[j] = 0;
                }
                sw.Stop();
                Console.WriteLine("for " + sw.ElapsedTicks);
                sw.Reset();
                sw.Start();
                Array.Clear(a, 0, a.Length);
                sw.Stop();
                Console.WriteLine("Array.Clear " + sw.ElapsedTicks);
            }
        }
    }
}

我的机器上的输出:

for 1166
Array.Clear 80
for 1136
Array.Clear 91
for 1350
Array.Clear 71
for 1028
Array.Clear 72
for 962
Array.Clear 54
for 1185
Array.Clear 46
for 962
Array.Clear 55
for 1091
Array.Clear 55
for 988
Array.Clear 54
for 1046
Array.Clear 55

所以Array.Clearfor loop 快大约 20 倍。但是Array.Clear 初始化为0。我可以以某种方式以相同的性能将数组初始化为-1 吗?

upd: 我不是在寻找一些“极度不安全”的代码。我正在寻找像Array.Clear 这样简单的东西。我只是想知道 .NET 提供快速 0 初始化,但 .NET 不提供对其他值的初始化。那么为什么 .NET 更喜欢“0”而不是“-1”呢?

upd 我想重置现有的数组。所以我正在寻找Array.Clear 的模拟,它将数组重置为-1,而不是0

【问题讨论】:

  • 你不应该用这么少的测试这么快就得出这样的结论。您应该使用更大的数组(远远超过 1000 个,但您现在很好)和更多的迭代(指数大于 10)并将它们平均化。
  • 我想知道您在做什么,将数组设置为相同的值(O(n) 操作)实际上需要大量时间。你真正想做什么?
  • @JeffMercado 更新代码,固定数组大小,增加到100000
  • @javapowered:这很好,一个不错的整数。但是您需要 更多 次重复此测试才能获得良好的基准。 10 是不够的。
  • @MikeBantegui 交易。在大多数应用程序中,您花费 500 µs 还是 495 µs 并不重要。在交易中,如果您花费 495 µs,您可能会赚钱,如果您花费 500 µs,您可能会亏钱。

标签: c#


【解决方案1】:

可能有一种方法可以通过非托管数组(指针)将连续的内存块设置为相同的值(例如,无论 int '-1' 在映射到其 4 字节内存时是什么)。

本文讨论了一种比托管 for 循环更快的方法(给出的示例是 byte[] 数组): http://techmikael.blogspot.com/2009/12/filling-array-with-default-value.html

另外,这里: What is the equivalent of memset in C#?

正如其他发帖人所提到的,这样做似乎有点极端,通常使用 for 循环初始化数组所需的速度不会有问题。

【讨论】:

  • 嘿...刚要添加int* 建议;你打败了我。
  • @Marc Gravell 呵呵,不用担心 - 如果需要,请随时编辑并添加代码示例
  • 我不需要“极端”。我只是想知道.NET 为我们提供了非常快速的“0 初始化”方法,但.NET 无法初始化为其他值。 “0”有什么好处?为什么“0”比“-1”好?
【解决方案2】:

嗯,最快的方法是使用静态初始化:

int[] a = {-1, -1, -1, -1, ...}

您总是可以编写一个程序来为您生成源代码,例如

var sb = new StringBuilder("int[] a = {");
for (int i = 0; i < 10000; ++i)
    sb.append(i != 10000 -1 ? "-1," : "-1");
sb.append("};");

【讨论】:

  • 这是一个有趣的解决方案。但是经常调用这样的初始化是否会花费太多的内存来为 GC 添加额外的工作?
  • 这与 GC 无关,编译器会在构建时完成所有工作。根据变量a 是什么(全局/静态或堆栈本地),在运行时实际上可能不会对性能产生任何影响。
  • 这与仅使用展开循环没有太大区别,但由于它分配了一个新数组,它与 GC 非常确实相关。问题是关于重置现有数组。
  • @Marc 好吧,标题是“如何初始化数组”......我猜OP的问题不是很清楚。如果编译器在编译时没有在某处的数据段中生成数组,这只是一个展开的循环。
  • @MahmoudAl-Qudsi 如果我只进行一次此操作,那么节省时间是没有意义的。我经常重复。
【解决方案3】:

我不知道它是否快,但是初始化数组的一种更清洁的方式。

int[] a = Enumerable.Range(0, 100000).Select(s => -1).ToArray();

更新: 或者更准确地说

int[] a = Enumerable.Repeat(-1, 100000).ToArray();

【讨论】:

  • 我想这都是你习惯的问题。在我看来,没有哪个宇宙比简单的for 循环更“干净”或更清晰!
  • +1 是的,最后是个人选择。 Lambda 表达式通常比迭代器更受欢迎,这可能是因为它的精确性,但我仍然同意它的个人偏好。
  • 不,不,不。有一个Repeat 方法。所以int[] a = Enumerable.Repeat(-1, 100000).ToArray();:
  • Enumerable.Repeat 肯定比迭代枚举数组要慢。任何客观的单元测试都会证明这一点。
【解决方案4】:

没有这样的东西 - 请参阅 this questionthis one

疯狂的理论 - 如果该方法是在非托管代码中实现的,那么Clear() 数组可能会更快。但请注意@JeffMercado 关于更大样本量的评论。

【讨论】:

  • Clear() 不会截断数组。这些不是动态数组,它们是原始数组。
  • 我不知道。我会编辑我的答案。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-27
  • 1970-01-01
  • 1970-01-01
  • 2020-09-29
  • 1970-01-01
  • 2018-04-05
相关资源
最近更新 更多