Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Containskey VS Try Catch

I have a list of Vector2's Generated I have to check against a dictionary to see if they exist, this function gets executed every tick.

which would run fastest/ be better to do it this way?

    public static bool exists(Vector2 Position, Dictionary<Vector2, object> ToCheck)
    {
        try
        {
            object Test = ToCheck[Position];
            return (true);
        }
        catch 
        {
            return (false);
        }           
    }

Or should I stick with The norm ?

    public static bool exists(Vector2 Position, Dictionary<Vector2, object> ToCheck)
    {
        if (ToCheck.ContainsKey(Position))
        {
            return (true);
        }
        return (false);
    }

Thanks for the input :)

Side Note: (The Value for the key doesn't matter at this point or i would use TryGetValue instead of ContainsKey)

like image 367
Dusty Avatar asked Sep 14 '12 00:09

Dusty


People also ask

When should I use try catch C#?

The C# try and catch keywords are used to define a try catch block. A try catch block is placed around code that could throw an exception. If an exception is thrown, this try catch block will handle the exception to ensure that the application does not cause an unhandled exception, user error, or crash the application.

What can I use instead of try catch in Java?

But anyhow, even without them, Vavr Try is a real alternative for Java try-catch blocks if you want to write more functional-style code.

What is try catch in C sharp?

The try-catch statement consists of a try block followed by one or more catch clauses, which specify handlers for different exceptions. When an exception is thrown, the common language runtime (CLR) looks for the catch statement that handles this exception.

What does TryGetValue do?

TryGetValue Method: This method combines the functionality of the ContainsKey method and the Item property. If the key is not found, then the value parameter gets the appropriate default value for the value type TValue; for example, 0 (zero) for integer types, false for Boolean types, and null for reference types.


2 Answers

I know it's an old question, but just to add a bit of empirical data...

Running 50,000,000 look-ups on a dictionary with 10,000 entries and comparing relative times to complete:

..if every look-up is successful:

  • a straight (unchecked) run takes 1.2 seconds
  • a guarded (ContainsKey) run takes 2 seconds
  • a handled (try-catch) run takes 1.21 seconds

..if 1 out of every 10,000 look-ups fail:

  • a guarded (ContainsKey) run takes 2 seconds
  • a handled (try-catch) run takes 1.37 seconds

..if 16 out of every 10,000 look-ups fail:

  • a guarded (ContainsKey) run takes 2 seconds
  • a handled (try-catch) run takes 3.27 seconds

..if 250 out of every 10,000 look-ups fail:

  • a guarded (ContainsKey) run takes 2 seconds
  • a handled (try-catch) run takes 32 seconds

..so a guarded test will add a constant overhead and nothing more, and try-catch test will operate almost as fast as no test if it never fails, but kills performance proportionally to the number of failures.

Code I used to run tests:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
   class Program
   {
      static void Main(string[] args)
      {  Test(0);
         Test(1);
         Test(16);
         Test(250);
      }

      private static void Test(int failsPerSet)
      {  Dictionary<int, bool> items = new Dictionary<int,bool>();

         for(int i =  0; i < 10000; i++)
            if(i >= failsPerSet)
               items[i] = true;

         if(failsPerSet == 0)
            RawLookup(items, failsPerSet);

         GuardedLookup(items, failsPerSet);

         CaughtLookup(items, failsPerSet);

      }

      private static void RawLookup
      (  Dictionary<int, bool> items
      ,  int             failsPerSet
      ){ int                   found = 0;
         DateTime              start ;

         Console.Write("Raw     (");
         Console.Write(failsPerSet);
         Console.Write("): ");

         start = DateTime.Now;
         for(int i = 0; i < 50000000; i++)
         {  int pick = i % 10000;
            if(items[pick])
               found++;
         }

         Console.WriteLine(DateTime.Now - start);
      }

      private static void GuardedLookup
      (  Dictionary<int, bool> items
      ,  int             failsPerSet
      ){ int                   found = 0;
         DateTime              start ;

         Console.Write("Guarded (");
         Console.Write(failsPerSet);
         Console.Write("): ");

         start = DateTime.Now;
         for(int i = 0; i < 50000000; i++)
         {  int pick = i % 10000;
            if(items.ContainsKey(pick))
               if(items[pick])
                  found++;
         }

         Console.WriteLine(DateTime.Now - start);
      }

      private static void CaughtLookup
      (  Dictionary<int, bool> items
      ,  int             failsPerSet
      ){ int                   found = 0;
         DateTime              start ;

         Console.Write("Caught  (");
         Console.Write(failsPerSet);
         Console.Write("): ");

         start = DateTime.Now;
         for(int i = 0; i < 50000000; i++)
         {  int pick = i % 10000;
            try
            {  if(items[pick])
                  found++;
            }
            catch
            {  
            }
         }

         Console.WriteLine(DateTime.Now - start);
      }

   }
}
like image 152
Eliott Avatar answered Oct 27 '22 07:10

Eliott


Definitely use the ContainsKey check; exception handling can add a large overhead.

Throwing exceptions can negatively impact performance. For code that routinely fails, you can use design patterns to minimize performance issues.

Exceptions are not meant to be used for conditions you can check for.

I recommend reading the MSDN documentation on exceptions generally, and on exception handling in particular.

like image 35
McGarnagle Avatar answered Oct 27 '22 07:10

McGarnagle