Performance Issues with Delegates

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • jehugaleahsa@gmail.com

    Performance Issues with Delegates

    I wrote a simple method that allows me to pass a delegate to find a
    value in a list. I already had a set of methods for doing comparisons:
    less, greater, equal, equivalent, etc. However, find algorithms always
    compare the element in the list to a given value. In other words, I
    needed to bind one value for all the comparisons.

    I wrote a simple Bind1st method that looks like this:

    public delegate R Operation<R, T>(T value);

    public delegate R Operation2<R, T>(T lhs, T rhs);

    public static Operation<R, TBind1st<R, T>(Operation2<R , T>
    operation, T lhs)
    {
    return delegate(T rhs)
    {
    return operation(lhs, rhs);
    };
    }

    However, when I run my find method with the Bind1st it runs *much*
    slower. I understand that the bind has to call a method each time;
    however, I can't see why that would cause the performance hit I am
    experiencing. I have tried putting the delegate inline with the value
    hard-coded as well and it runs much better. My code performs best when
    no delegates are involved at all (but this means not using my find
    method).

    Any suggestions for getting away from the wall?

    Thanks,
    Travis

  • Peter Duniho

    #2
    Re: Performance Issues with Delegates

    jehugaleahsa@gm ail.com wrote:
    I wrote a simple method that allows me to pass a delegate to find a
    value in a list. I already had a set of methods for doing comparisons:
    less, greater, equal, equivalent, etc. However, find algorithms always
    compare the element in the list to a given value. In other words, I
    needed to bind one value for all the comparisons.
    >
    I wrote a simple Bind1st method that looks like this:
    >
    public delegate R Operation<R, T>(T value);
    >
    public delegate R Operation2<R, T>(T lhs, T rhs);
    >
    public static Operation<R, TBind1st<R, T>(Operation2<R , T>
    operation, T lhs)
    {
    return delegate(T rhs)
    {
    return operation(lhs, rhs);
    };
    }
    >
    However, when I run my find method with the Bind1st it runs *much*
    slower.
    First, I don't understand the code you posted. It won't compile, due to
    the missing semicolon, but also the Bind1st<R, Tmethod never calls the
    operation delegate. Why have that block of code at all?

    Second, you haven't posted nearly enough code to really describe your
    problem. What are your delegate methods doing? How do you use
    Bind1st<R, Tin real code? What are the _actual_ time differences for
    different implementations ? That is, you need to define "much slower".

    Obviously, calling a method by reference, such as using a delegate or
    virtual method or similar, is going to be slower than calling a method
    directly. But in practice this is almost never an issue. The act of
    calling any method is so inexpensive compared to code that does anything
    interesting, it's almost never an issue.

    But there's not really enough context in your question to be able to
    provide useful, specific advice. You should post a concise-but-complete
    example of code that reliably reproduces the problem. This would
    include demonstrating the time cost of the two implementations you're
    comparing.

    Pete

    Comment

    • jehugaleahsa@gmail.com

      #3
      Re: Performance Issues with Delegates

      Ask and you shall receive.

      public static IIterator<TFind <T>(IIterator<T first,
      IIterator<Tpast , Predicate<Tpred icate)
      {
      if (first == null)
      {
      throw new ArgumentNullExc eption();
      }
      if (past == null)
      {
      throw new ArgumentNullExc eption();
      }
      if (predicate == null)
      {
      throw new ArgumentNullExc eption();
      }
      first = first.Clone();
      while (!first.Equals( past) && !predicate(firs t.Current))
      {
      first.Next();
      }
      return first;
      }

      public static bool Equivalent<T>(T lhs, T rhs)
      {
      return Object.Referenc eEquals(lhs, rhs) || lhs != null &&
      lhs.Equals(rhs) ;
      }

      Algorithms.Find <T>(list.GetFir st(),
      list.GetPast(),
      new Predicate<T>(Fu nctional.Bind1s t<bool,
      T>(Functional.E quivalent<T>, value)));

      These are merely snippets. There is a library of data structures that
      provided iterators; list is a doubly-linked list. If you have ever
      worked in C++, this should certainly seem familiar.

      Just so you know, I copied that code from a working set. It was inside
      a class, so that might explain your compile error. I am not sure what
      you mean by a missing semicolon; it looks fine to me.

      I figured someone would ask what "much slower" meant. I am not talking
      factors of N, of course. I am talking something that runs in 19
      seconds taking 59 seconds, something taking 17 minutes taking 45
      minutes. That is significant enough even if it isn't a factor of N.
      These are real times, by the way.

      Comment

      • Jon Skeet [C# MVP]

        #4
        Re: Performance Issues with Delegates

        jehugaleahsa@gm ail.com <jehugaleahsa@g mail.comwrote:

        <snip>
        I figured someone would ask what "much slower" meant. I am not talking
        factors of N, of course. I am talking something that runs in 19
        seconds taking 59 seconds, something taking 17 minutes taking 45
        minutes. That is significant enough even if it isn't a factor of N.
        These are real times, by the way.
        Are you running inside the debugger? That could well have a significant
        impact.

        If you could post a short but *complete* program which demonstrates the
        problem, including the performance issue, we're much more likely to
        have a chance of sorting it out.

        --
        Jon Skeet - <skeet@pobox.co m>
        http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
        If replying to the group, please do not mail me too

        Comment

        • =?ISO-8859-1?Q?G=F6ran_Andersson?=

          #5
          Re: Performance Issues with Delegates

          jehugaleahsa@gm ail.com wrote:
          I wrote a simple method that allows me to pass a delegate to find a
          value in a list. I already had a set of methods for doing comparisons:
          less, greater, equal, equivalent, etc. However, find algorithms always
          compare the element in the list to a given value. In other words, I
          needed to bind one value for all the comparisons.
          >
          I wrote a simple Bind1st method that looks like this:
          >
          public delegate R Operation<R, T>(T value);
          >
          public delegate R Operation2<R, T>(T lhs, T rhs);
          >
          public static Operation<R, TBind1st<R, T>(Operation2<R , T>
          operation, T lhs)
          {
          return delegate(T rhs)
          {
          return operation(lhs, rhs);
          };
          }
          >
          However, when I run my find method with the Bind1st it runs *much*
          slower. I understand that the bind has to call a method each time;
          however, I can't see why that would cause the performance hit I am
          experiencing. I have tried putting the delegate inline with the value
          hard-coded as well and it runs much better. My code performs best when
          no delegates are involved at all (but this means not using my find
          method).
          >
          Any suggestions for getting away from the wall?
          >
          Thanks,
          Travis
          >
          As the delegate that you create in the method is using one of the
          parameters from the method, the delegate is not just a pointer to a
          method any more. Instead the compiler has to package the delegate along
          with the value of the parameter.

          I don't know exactly how this is done, but it's certainly more
          complicated than just using a pointer, so there is the reason for the
          difference in performance.

          --
          Göran Andersson
          _____
          Göran Anderssons privata hemsida.

          Comment

          • Jon Skeet [C# MVP]

            #6
            Re: Performance Issues with Delegates

            Göran Andersson <guffa@guffa.co mwrote:
            As the delegate that you create in the method is using one of the
            parameters from the method, the delegate is not just a pointer to a
            method any more. Instead the compiler has to package the delegate along
            with the value of the parameter.

            I don't know exactly how this is done, but it's certainly more
            complicated than just using a pointer, so there is the reason for the
            difference in performance.
            It's not that complicated - it's just creating an instance of a type
            which has been created behind the scenes.

            Object creation is very fast for simple cases - I don't think it's
            likely to account for this slowdown.

            --
            Jon Skeet - <skeet@pobox.co m>
            http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
            If replying to the group, please do not mail me too

            Comment

            • =?ISO-8859-1?Q?G=F6ran_Andersson?=

              #7
              Re: Performance Issues with Delegates

              Jon Skeet [C# MVP] wrote:
              jehugaleahsa@gm ail.com <jehugaleahsa@g mail.comwrote:
              >
              <snip>
              >
              >I figured someone would ask what "much slower" meant. I am not talking
              >factors of N, of course. I am talking something that runs in 19
              >seconds taking 59 seconds, something taking 17 minutes taking 45
              >minutes. That is significant enough even if it isn't a factor of N.
              >These are real times, by the way.
              >
              Are you running inside the debugger? That could well have a significant
              impact.
              >
              If you could post a short but *complete* program which demonstrates the
              problem, including the performance issue, we're much more likely to
              have a chance of sorting it out.
              >
              Here's a short but complete program.

              using System;
              using System.Collecti ons.Generic;
              using System.Text;
              using System.Diagnost ics;

              namespace UnitTest {

              class Program {

              private static void Main(string[] args) {
              TestDelegates() ;
              }

              #region Clock

              private static Stopwatch clock = new Stopwatch();

              private static void Start() {
              clock.Reset();
              clock.Start();
              }

              private static void Stop() {
              Stop("Time: {0:N3} seconds.");
              }

              private static void Stop(string format) {
              clock.Stop();
              Console.WriteLi ne(format, clock.Elapsed.T otalSeconds);
              }

              #endregion

              public delegate R Operation<R, T>(T value);
              public delegate R Operation2<R, T>(T left, T right);

              public static Operation<R, TBind<R, T>(Operation2<R , Toperation, T
              left) {
              return delegate(T right) { return operation(left, right); };
              }

              public static bool StringEqual(str ing left, string right) {
              return left == right;
              }

              public static List<TFind<T>(L ist<Tsource, T value,
              Operation2<bool , Toperation) {
              List<Tresult = new List<T>();
              foreach (T t in source) {
              if (operation(t, value)) {
              result.Add(t);
              }
              }
              return result;
              }

              public static List<TFind<T>(L ist<Tsource, Operation<bool, T>
              operation) {
              List<Tresult = new List<T>();
              foreach (T t in source) {
              if (operation(t)) {
              result.Add(t);
              }
              }
              return result;
              }

              private static void TestDelegates() {
              int iterations = 1000000;
              List<stringsour ce = new List<string>(ne w string[] { "a", "b", "c",
              "d", "e", "f", "g" } );
              Start();
              for (int i = 0; i < iterations; i++) {
              List<stringresu lt = Find<string>(so urce, "c", StringEqual);
              }
              Stop();
              Start();
              for (int i = 0; i < iterations; i++) {
              List<stringresu lt = Find<string>(so urce, Bind<bool,
              string>(StringE qual, "c"));
              }
              Stop();
              }

              }

              }


              --
              Göran Andersson
              _____
              Göran Anderssons privata hemsida.

              Comment

              • Jon Skeet [C# MVP]

                #8
                Re: Performance Issues with Delegates

                Göran Andersson <guffa@guffa.co mwrote:
                Are you running inside the debugger? That could well have a significant
                impact.

                If you could post a short but *complete* program which demonstrates the
                problem, including the performance issue, we're much more likely to
                have a chance of sorting it out.
                Here's a short but complete program.
                Right. Thanks for that :)

                It looks like the delegate creation is indeed the issue here - moving
                the call to Bind outside the loop makes the performance basically the
                same for both cases.

                So, really we need to ask the OP if they can do the same thing...

                --
                Jon Skeet - <skeet@pobox.co m>
                http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
                If replying to the group, please do not mail me too

                Comment

                Working...