3

I understand that I should not optimize every single point of my program, let's just assume that I have to optimize array initialization.

So I wrote program that compares for loop versus Array.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);
            }
        }
    }
}

Output on my machine:

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

So Array.Clear is about 20 times faster than for loop. But Array.Clear initializes to 0. Can I initialize array to -1 with the same perfomance somehow?

upd: I'm not looking for some "extreme unsafe" code. I'm looking for something as easy as Array.Clear. I just wonder that .NET offers fast 0 initialization, but .NET doesn't offer initialization to other values. So why .NET like "0" much more than "-1"?

upd I want to reset existent array. So i'm looking for analog of Array.Clear which will reset array to -1, not 0

Oleg Vazhnev
  • 23,239
  • 54
  • 171
  • 305
  • 2
    You shouldn't jump to such conclusions so quickly with so few tests. You should work with larger arrays (much more than 1000, but you're fine now) and way more iterations (exponentially larger than just 10) and average them off. – Jeff Mercado May 19 '12 at 06:10
  • I would like to know what you're doing where setting an array to the same value (an O(n) operation) is actually taking a significant amount of time. What are you really trying to do? – Mike Bailey May 19 '12 at 06:15
  • @JeffMercado updated code, fixed array size, increased to `100000` – Oleg Vazhnev May 19 '12 at 06:17
  • @javapowered: And that's fine, a nice round number. But you need _many_ more iterations repeating this test to get a good benchmark. 10 is just not enough. – Jeff Mercado May 19 '12 at 06:19
  • @MikeBantegui trading. in most applications it doesn't matter if you spent 500 µs or 495 µs. In trading it's possible that if you spent 495 µs you earn money, if you spent 500 µs you loose money. – Oleg Vazhnev May 19 '12 at 06:19
  • @JeffMercado increasing number of iterations doesn't change picture. `Array.Clear` dozens times faster. – Oleg Vazhnev May 19 '12 at 06:20
  • What if you simply re initialize the array `a = new int[10000]`. That will be faster. – Rahul May 19 '12 at 06:23
  • @Rahul you don't like GC? :) assuming that I need to do this pretty ofthen I will have a lot of garbage – Oleg Vazhnev May 19 '12 at 06:26
  • @javapowered: If you're going to time things, then you should take a large sample count and provide some error bounds. See here: http://pastebin.com/PmjxKGD6. This gives me something like 358 +/- 60 ticks for `for` and 64 +/- 5 ticks for `Clear`. – Mike Bailey May 19 '12 at 06:31
  • @javapowered: Also, you still haven't really answered my question. Is setting an array to a constant really taking *that* much time? I would be seriously worried if that was the case. Have you profiled and seen that this actually takes a significant amount of CPU time? – Mike Bailey May 19 '12 at 06:36
  • @MikeBantegui no i not profilied. I will spent more time to profile and analyze application than to find one of the fastest solutions. I just write "hotpoints" as fast as I can, without profiling. You should probably use `Stopwatch.Reset() Stopwatch.Start()` instead of `Stopwatch.StartNew()`. If some easy and fast and readable method exists to initialize to `-1` why just don't use it? – Oleg Vazhnev May 19 '12 at 07:24
  • @javapowered: You're missing the point. You can optimize something as much as you want, but unless it's actually taking a significant amount of CPU time in your application you're wasting your time. – Mike Bailey May 19 '12 at 16:31
  • @MikeBantegui I enjoy wasting my time. Question was not about should I or should not, question was about "how" and I wrote this in the first sequence. Just threat this question as "theoretical" if you wish. – Oleg Vazhnev May 20 '12 at 11:02

4 Answers4

6

There's probably a way to do it via unmanaged arrays (pointers) to set the contiguous block of memory to the same value (e.g. whatever the int '-1' is when mapped into its 4-bytes of memory).

This article here discusses a faster method than with a managed for loop (example given is a byte[] array): http://techmikael.blogspot.com/2009/12/filling-array-with-default-value.html

Also, here: What is the equivalent of memset in C#?

As other posters have mentioned, it seems a bit extreme to do this though, and normally the speed required to initialise the array using a for loop would not be a problem.

Community
  • 1
  • 1
dodgy_coder
  • 12,407
  • 10
  • 54
  • 67
  • Heh... Was just about to add an `int*` suggestion; you beat me to it. – Marc Gravell May 19 '12 at 06:45
  • @Marc Gravell hehe no worries - feel free to edit it and add a code sample if you want – dodgy_coder May 19 '12 at 06:47
  • I don't need "extreme". I just wonder that .NET offers us very fast "0 initialization" method, but .NET can't initialize to other values. What are benefits of "0"? Why "0" is better than "-1"? – Oleg Vazhnev May 20 '12 at 11:06
2

Well, the fastest way would be to use static initialization:

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

You could always write a program to generate the source code for that for you, e.g.

var sb = new StringBuilder("int[] a = {");
for (int i = 0; i < 10000; ++i)
    sb.append(i != 10000 -1 ? "-1," : "-1");
sb.append("};");
Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
  • it's interesting solution. but having such initialization called to often will I spent too much memory adding extra work to GC? – Oleg Vazhnev May 19 '12 at 06:25
  • 1
    This has nothing to do with the GC, it's the compiler that'll do all the work at build time. Depending on what the variable `a` is (global/static or stack-local), there could actually be no performance impact at runtime whatsoever. – Mahmoud Al-Qudsi May 19 '12 at 06:29
  • This isn't very different to just having an unrolled loop, but since it allocates a new array it very much **does** relate to GC. The question is about resetting an existing array. – Marc Gravell May 19 '12 at 06:43
  • @Marc well the title is "how to *initialize* array"... I guess the OP's question isn't very clear. It's only like an unrolled loop if the compiler doesn't generate the array at compile time in a data section somewhere. – Mahmoud Al-Qudsi May 19 '12 at 06:52
  • @MahmoudAl-Qudsi it doesn't make sense to save time if I make this operation only once. I repeat it very often. – Oleg Vazhnev May 20 '12 at 11:04
  • It could well be correct that this is a fast way to initialize the array. It looks like the compiler somehow puts the data in a field of a generated class named `{some guid}`. It then generates code to call [RuntimeHelpers.InitializeArray](http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.initializearray.aspx). – Jeppe Stig Nielsen Feb 17 '13 at 09:00
2

I don't know that whether it is fast or not, but a cleaner way to initialize an array .

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

UPDATE: Or more precisely

int[] a = Enumerable.Repeat(-1, 100000).ToArray();
Asif Mushtaq
  • 13,010
  • 3
  • 33
  • 42
  • 1
    I suppose it's all a matter of what you get used to. In no universe is that symbolic jumble "cleaner" or clearer to me than a simple `for` loop! – Cody Gray - on strike May 19 '12 at 08:20
  • +1 Yes, at the end its a personal choice. Lambda expressions are generally preferred over iterators, it might be due to its preciseness, but still I agree that its personal preference. – Asif Mushtaq May 19 '12 at 08:24
  • 2
    No, no, no. There's a `Repeat` method for that. So `int[] a = Enumerable.Repeat(-1, 100000).ToArray();`: – Jeppe Stig Nielsen May 19 '12 at 10:34
  • Enumerable.Repeat is definitely slower that iterating to enumerate an array. Any objective unit tests will show that. – Christian Findlay Aug 23 '19 at 01:51
0

No such thing - see this question and this one.

Crazy theory - it could be faster to Clear() the array if that method was implemented in non-managed code. But note @JeffMercado's comment about larger sample sizes.

Community
  • 1
  • 1
Rob I
  • 5,627
  • 2
  • 21
  • 28