-1

When I do binary search, I use a recursive local function to deal with the elements in the tree. but in most of cases, it is not as efficient as a non-local function version. I'm not sure why is it happend. Is local function more consuming?

enter image description here

local function version:

       internal void Next2(Action<int?> sProcess)
        {//
            var Process = sProcess;
            Next3(this);

            #region Local func
            void Next3(Node L) { 
            if (L.LeftChild == null && L.RightChild == null) {
                Process?.Invoke(this.Element);
            }
            else {
                if (L.LeftChild != null) {
                        Next3(L.LeftChild);
                }
                if (L.RightChild != null) {
                        Next3(L.RightChild);
                }
            }

            }
            #endregion
        }

non-local function version:

        internal void Next(Action<int?> Process) //
        {//[[this!!]]
            if (LeftChild == null && RightChild == null) {
                Process?.Invoke(this.Element);
            }
            else {
                if (LeftChild != null) {
                    this.LeftChild.Next(Process);
                }
                if (RightChild != null) {
                    this.RightChild.Next(Process);
                }
            }

        }
Jianjie
  • 107
  • 5
  • 1
    Use this opportunity to learn about the visitor pattern – Moho Aug 25 '21 at 19:39
  • 1
    These functions are not equivalent. `Next3` accesses `this.Element`, when it should be accessing `L.Element`. Even with that it needs a closure to capture `Process` in addition to the local parameter, so it has one more than `Next`. It's not much overhead, but it is overhead. It's not clear what you think the advantage of a local function here would be in any case, since `Next2` does nothing interesting before calling `Next3`. There are cases where a local function can simplify/streamline recursion by not having to expose a helper function, but this doesn't seem to be one of them. – Jeroen Mostert Aug 25 '21 at 19:52
  • Does this answer your question? [Are value type variables declared in local function stack-allocated?](https://stackoverflow.com/questions/55744208/) and [Why measuring the execution time of a loop gives different results execution after execution?](https://stackoverflow.com/questions/58678348/) –  Aug 25 '21 at 19:52

1 Answers1

4

Local functions can, in fact, close over the outer scope of their containing methods. When this happens, the compiler generates types for them that are used to capture the variables of the containing scope; these new types are often stored on the heap, increasing memory pressure and leading to more garbage collections.

Increased garbage collections result in reduced performance. How significant that performance hit is can vary, and whether or not you should concern yourself with it is a debate for philosophers and software engineers far more experienced than I am.

For your specific scenario (a recursive local function), I would advise the following: If the local function references variables outside its own scope, refactor it so that it takes all the data it needs as arguments. In this way, it is no longer a closure, and the compiler won't generate a type for it that places additional memory pressure on the heap.

If this isn't practical, use a standard, non-local method.

Mike Hofer
  • 16,477
  • 11
  • 74
  • 110
  • Thank you for guiding me deep into the GC aspect, which really helps! I had done some more about my code soon afterwards. – Jianjie Aug 27 '21 at 10:12