tags:

views:

102

answers:

4

When using Array.GetLength(dimension) in C#, does the size of the array actually get calculated each time it is called, or is the size cached/stored and that value just gets accessed?

What I really want to know is if setting a local variable to the length of the dimension of an array would add any efficiency if used inside a big loop or if I can just call array.GetLength() over and over w/o any speed penalty.

A: 

It is probably inserted at compile time if it is known then. Otherwise, stored in a variable. If it weren't, how would the size be calculated?

However, you shouldn't make assumptions about the internal operations of the framework. If you want to know if something is more or less efficient, test it!

Brennan Vincent
+7  A: 

It is most certainly a bad idea to start caching/optimizing by yourself here.

When dealing with arrays, you have to follow a standard path that the (JIT) optimizer can recognize. If you do, not only will the Length property be cached but more important the index bounds-check can be done just once before the loop.

When the optimizer loses your trail you will pay the penalty of a per-access bounds-check.

This is why jagged arrays (int[][]) are faster than multi-dim (int[,]). The optimization for int[,] is simply missing. Up to Fx2 anyway, I didn't check the status of this in Fx4 yet.

If you want to research this further, the caching you propose is usually called 'hoisting' the Length property.

Henk Holterman
Also, the documentation states "This method is an O(1) operation", suggesting the overhead is minimal.
nos
A: 

The naming convention is a clue. THe "Length" methods (e.g. Array.Length) in .net typically return a known value, while the "Count" methods (e.g. List.Count) will/may enumerate the contents of the collection to work out the number of items. (In later .nets there are extension methods like Any that allow you to check if a collection is non-empty without having to use the potentially expensive Count operation) GetLength should only differ from Length in that you can request the dimension you want the length of.

A local variable is unlikely to make any difference over a call to GetLength - the compiler will optimise most situations pretty well anyway - or you could use foreach which does not need to determine the length before it starts.

(But it would be easy to write a couple of loops and time them (with a high performance counter) to see what effect different calls/types might have on the execution speed. Doing this sort of quick test can be a great way of gaining insights into a language that you might not really take in if you just read the answers)

Jason Williams
@Henk: foreach may not be faster, but it certainly won't be slower. (As you said, doing things like caching the length could actually make things worse, while foreach gives the optimiser the best chance of success)
Jason Williams
This is unbelievably wrong. The `Count` property on `ICollection<T>` is conventionally implemented to be very fast; it's just a cached field on a `List<T>`. It absolutely does not enumerate the collection on any framework collection. `Any()` does enumerate the (first element of) the collection. `Count()` calls `Count` if it's an `ICollection`, and otherwise enumerates the collection.
mquander
I said Count *may* enumerate the collection. This *may* (on some collections) be slower than the typical implementation of Length, which will not conventionally enumerate anything. The exact implementation of Count depends on the Collection you are using. This is *why* Microsoft used the Count/Length naming convention. Perhaps Eric Lippert can convince you: http://blogs.msdn.com/b/ericlippert/archive/2008/05/09/computers-are-dumb.aspx
Jason Williams
Nope, he can't. That blog post describes `Enumerable.Count()` as enumerating the collection, but never the `Count` property. If you really think that `Count` may enumerate the collection, then point me to one single framework type where it does so; I don't believe there are any. I would be shocked to see an example. (Also, I was under the impression that the convention was to use `Count` for variable length collections and `Length` for fixed-size collections (e.g. strings as well as arrays.))
mquander
OK, fair enough, I missed some brackets when reading. Thanks for the pointer - it's good to learn new things.
Jason Williams
A: 

If you really need the loop to be as fast as possible, you can store the length in a variable. This will give you a slight performance increase, some quick testing that I did shows that it's about 30% faster.

As the difference isn't bigger, it shows that the GetLength method is really fast. Unless you really need to cram the last out of the code, you should just use the method in the loop.

This goes for multidimensional arrays, only. For a single dimensional array it's actually faster to use the Length property in the loop, as the optimiser then can remove bounds checks when you use the array in the loop.

Guffa
Somebody who only reads your first sentence will start doing the wrong thing here. Your 30% gain is for the rare, sub-optimal case only.
Henk Holterman