Containskey VS Try Catch

У меня есть список сгенерированных Vector2, я должен проверить по словарю, чтобы увидеть, если они существуют, эта функция выполняется каждый тик.

который будет работать быстрее / лучше сделать так?

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

Или я должен придерживаться нормы?

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

Спасибо за вклад:)

Примечание: (Значение для ключа на данном этапе не имеет значения, иначе я бы использовал TryGetValue вместо ContainsKey)

4 ответа

Решение

Определенно используйте ContainsKey проверять; обработка исключений может добавить большие накладные расходы.

Бросать исключения могут отрицательно повлиять на производительность. Для кода, который обычно терпит неудачу, вы можете использовать шаблоны проектирования, чтобы минимизировать проблемы с производительностью.

Исключения не предназначены для использования в условиях, которые вы можете проверить.

Я рекомендую прочитать документацию MSDN об исключениях в целом и об обработке исключений в частности.

Я знаю, что это старый вопрос, но просто добавить немного эмпирических данных...

Выполнение 50 000 000 просмотров в словаре с 10 000 записей и сравнение относительного времени для завершения:

..Если каждый просмотр успешен:

  • прямой (неконтролируемый) забег занимает 1,2 секунды
  • защищенный (ContainsKey) забег занимает 2 секунды
  • обработанный (try-catch) запуск занимает 1,21 секунды

..Если 1 из каждых 10 000 поисков не выполняется:

  • защищенный (ContainsKey) забег занимает 2 секунды
  • обработанный (try-catch) пробег занимает 1,37 секунды

..if 16 из каждых 10 000 поисков не удаются:

  • защищенный (ContainsKey) забег занимает 2 секунды
  • обработанный (try-catch) запуск занимает 3,27 секунды

..Если 250 из каждых 10 000 поисков не пройдены:

  • защищенный (ContainsKey) забег занимает 2 секунды
  • обработанный (try-catch) запуск занимает 32 секунды

... так что защищенный тест добавит постоянные накладные расходы и ничего более, и тест try-catch будет работать почти так же быстро, как и любой тест, если он никогда не завершится неудачей, но убивает производительность пропорционально количеству сбоев.

Код, который я использовал для запуска тестов:

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);
      }

   }
}

Примечание: (Значение для ключа на данном этапе не имеет значения, иначе я бы использовал TryGetValue вместо ContainsKey)

Ответ, который вы приняли, является правильным, но просто добавьте, если вам важен только ключ, а не значение, возможно, вы ищете HashSet а не Dictionary?

Кроме того, ваш второй фрагмент кода является методом, который буквально добавляет нулевое значение. Просто используйте ToCheck.ContainsKey(Position), не создавайте метод, который просто вызывает этот метод и возвращает его значение, но больше ничего не делает.

Никогда не используйте try/catch как часть вашего обычного пути к программе. Это действительно дорого и должно отлавливать только ошибки, которые вы не можете предотвратить. ContainsKey это путь сюда.

Примечание стороны: Нет. Вы не будете. Если значение имеет значение, вы проверяете с помощью ContainsKey, существует ли оно, и извлекаете его, если оно существует. Не пробуй / лови.

Другие вопросы по тегам