7

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.

devuxer
  • 41,681
  • 47
  • 180
  • 292

4 Answers4

11

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.

Community
  • 1
  • 1
H H
  • 263,252
  • 30
  • 330
  • 514
  • 4
    Also, the documentation states "This method is an O(1) operation", suggesting the overhead is minimal. – nos Jul 04 '10 at 21:42
  • Just wanted to share a case I recently had, where this indeed was a problem. I was iterating a quite large 2 dimensional array multiple times per second. Profiler identified a bottleneck on array length property inside `for` loop. #1. `T[,]` with `.GetLength(0)` and `.GetLength(1)` supported ~4 mil elements. #2. `T[,]` with hoisted length properties allowed to jump to ~67 mil elements. #3. `T[][]` with `.Length` properties supported ~67 mil element but 30% slower. #4. `T[][]` with hoisted second dimension showed same results as #2. – Laurynas Lazauskas Jul 20 '20 at 21:20
0

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
  • 10,736
  • 9
  • 32
  • 54
0

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
  • 687,336
  • 108
  • 737
  • 1,005
  • 3
    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. – H H Jul 04 '10 at 21:59
-1

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
  • 56,972
  • 11
  • 108
  • 137
  • @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 Jul 04 '10 at 21:53
  • 3
    This is unbelievably wrong. The `Count` property on `ICollection` is conventionally implemented to be very fast; it's just a cached field on a `List`. 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. – mqp Jul 04 '10 at 22:05
  • 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 Jul 05 '10 at 07:26
  • 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.)) – mqp Jul 05 '10 at 16:36
  • 1
    OK, fair enough, I missed some brackets when reading. Thanks for the pointer - it's good to learn new things. – Jason Williams Jul 05 '10 at 19:53