2009-05-15 5 views
20

Я знаю, что исключения имеют штраф за производительность, и что обычно более эффективно пытаться избегать исключений, чем бросать большой try/catch во всем - но как насчет самого блока try ? Какова стоимость простого объявления try/catch, даже если он никогда не вызывает исключение?Производительность «Попробуйте» на C#

+8

Вы единственный человек, который может ответить на этот вопрос. Вы единственный человек, который знает, какое оборудование и программное обеспечение вы используете, вы единственный человек, который знает, какие показатели производительности имеют отношение к вашему клиенту, и так далее. Напишите некоторые реалистичные тесты, попробуйте их на реалистичном оборудовании, и тогда вы узнаете ответ. Любой, кто пытается ответить на ваш вопрос, либо догадывается, либо описывает характеристики производительности на своих машинах для своих клиентов, а не ваших. В любом случае, это не те данные, которые вам нужны. –

+0

@ Эрик - Хорошо сказано. –

ответ

26

Эксплуатационная стоимость попытки очень маленькая. Основная стоимость обработки исключений - это получение трассировки стека и других метаданных, и это затраты, которые не выплачиваются, пока вам не придется бросать исключение.

Но это будет зависеть от языка и реализации. Почему бы не написать простую петлю на C# и не занять ее самостоятельно?

+1

Да. Попробуйте бесплатно, потому что в основном его обрабатывают метаданные, которые действительно проверяются только тогда, когда исключение действительно выбрано. –

5

Общее высказывание, что исключения являются дорогостоящими, когда они пойманы - не бросили. Это связано с тем, что большинство сбора метаданных исключений (например, получение трассировки стека и т. Д.) Действительно происходит только на стороне try-catch (а не на стороне броска).

Развертывание стека на самом деле довольно быстро - CLR поднимает стек вызовов и только обращает внимание на блоки, которые он находит; ни в коем случае в чистом блоке try-finally во время выполнения попытка «завершить» исключение (это метаданные и т. д.).

Из того, что я помню, любые попытки уловов с фильтрами (такие как «catch (FooException) {}») так же дороги, даже если они ничего не делают с исключением.

Я бы рискнул сказать, что метод (назовем его CatchesAndRethrows) со следующим блоком:

try 
{ 
    ThrowsAnException(); 
} 
catch 
{ 
    throw; 
} 

может привести к более быстрому стека блуждания в методе - такие, как:

try 
{ 
    CatchesAndRethrows(); 
} 
catch (Exception ex) // The runtime has already done most of the work. 
{ 
    // Some fancy logic 
} 

Некоторые номера:

With: 0.13905ms 
Without: 0.096ms 
Percent difference: 144% 

Вот эта контрольная отметка, которую я запускал (помните, что режим выпуска - работать без deb UG):

static void Main(string[] args) 
    { 
     Stopwatch withCatch = new Stopwatch(); 
     Stopwatch withoutCatch = new Stopwatch(); 

     int iterations = 20000; 

     for (int i = 0; i < iterations; i++) 
     { 
      if (i % 100 == 0) 
      { 
       Console.Write("{0}%", 100 * i/iterations); 
       Console.CursorLeft = 0; 
       Console.CursorTop = 0; 
      } 

      CatchIt(withCatch, withoutCatch); 
     } 

     Console.WriteLine("With: {0}ms", ((float)(withCatch.ElapsedMilliseconds))/iterations); 
     Console.WriteLine("Without: {0}ms", ((float)(withoutCatch.ElapsedMilliseconds))/iterations); 
     Console.WriteLine("Percent difference: {0}%", 100 * withCatch.ElapsedMilliseconds/withoutCatch.ElapsedMilliseconds); 
     Console.ReadKey(true); 
    } 

    static void CatchIt(Stopwatch withCatch, Stopwatch withoutCatch) 
    { 
     withCatch.Start(); 

     try 
     { 
      FinallyIt(withoutCatch); 
     } 
     catch 
     { 
     } 

     withCatch.Stop(); 
    } 

    static void FinallyIt(Stopwatch withoutCatch) 
    { 
     try 
     { 
      withoutCatch.Start(); 
      ThrowIt(withoutCatch); 
     } 
     finally 
     { 
      withoutCatch.Stop(); 
     } 
    } 

    private static void ThrowIt(Stopwatch withoutCatch) 
    { 
     throw new NotImplementedException(); 
    } 
+1

Я думаю, что ОП спросил о влиянии производительности, когда исключения НЕ выбрасываются. – Shimmy

7

На самом деле, пару месяцев назад я создания веб-приложений ASP.NET, и я случайно завернул попробовать/поймать блок с очень длинной петлей. Несмотря на то, что цикл не генерировал никаких исключений, потребовалось слишком много времени для завершения. Когда я вернулся и увидел try/catch, завернутый в цикл, я сделал это наоборот, я завернул цикл в блок try/catch. Производительность улучшилась. Вы можете попробовать это самостоятельно: сделайте что-нибудь наподобие

int total; 

DateTime startTime = DateTime.Now; 

for(int i = 0; i < 20000; i++) 
{ 
try 
{ 
total += i; 
} 
catch 
{ 
// nothing to catch; 
} 
} 

Console.Write((DateTime.Now - startTime).ToString()); 

И затем выньте блок try/catch. Вы увидите большую разницу!

+11

Хммм. Я просто попробовал это на .Net 2.0 (используя «Секундомер»). 50000 испытаний 20000 циклов итераций занимает 4184 мс без 'try-catch', 4363ms с' try-catch'. Это невероятно маленькая разница. Такая разница будет еще менее заметна, если каждая итерация фактически выполняет что-то помимо простой операции добавления. Я ударил аналогичные результаты с и без отладки. – Brian

4

Чтобы увидеть, что действительно стоит, вы можете запустить код, указанный ниже. Он принимает простой двухмерный массив и генерирует случайные координаты, которые находятся за пределами допустимого диапазона. Если ваше исключение происходит только один раз, конечно, вы его не заметите. Мой пример делается для того, чтобы подчеркнуть, что это будет означать, когда вы делаете это несколько тысяч раз, и то, что поймает исключение против внедрения простого теста, спасет вас.

 const int size = 1000; 
     const int maxSteps = 100000; 

     var randomSeed = (int)(DateTime.UtcNow - new DateTime(1970,1,1,0,0,0).ToLocalTime()).TotalMilliseconds; 
     var random = new Random(randomSeed); 
     var numOutOfRange = 0; 
     var grid = new int[size,size]; 
     var stopwatch = new Stopwatch(); 
     Console.WriteLine("---Start test with exception---"); 
     stopwatch.Reset(); 
     stopwatch.Start(); 
     for (int i = 0; i < maxSteps; i++) 
     { 
      int coord = random.Next(0, size * 2); 
      try 
      { 
       grid[coord, coord] = 1; 
      } 
      catch (IndexOutOfRangeException) 
      { 
       numOutOfRange++; 
      } 
     } 
     stopwatch.Stop(); 
     Console.WriteLine("Time used: " + stopwatch.ElapsedMilliseconds + "ms, Number out of range: " + numOutOfRange); 
     Console.WriteLine("---End test with exception---"); 

     random = new Random(randomSeed); 

     stopwatch.Reset(); 
     Console.WriteLine("---Start test without exception---"); 
     numOutOfRange = 0; 
     stopwatch.Start(); 
     for (int i = 0; i < maxSteps; i++) 
     { 
      int coord = random.Next(0, size * 2); 
      if (coord >= grid.GetLength(0) || coord >= grid.GetLength(1)) 
      { 
       numOutOfRange++; 
       continue; 
      } 
      grid[coord, coord] = 1; 
     } 
     stopwatch.Stop(); 
     Console.WriteLine("Time used: " + stopwatch.ElapsedMilliseconds + "ms, Number out of range: " + numOutOfRange); 
     Console.WriteLine("---End test without exception---"); 
     Console.ReadLine(); 

Пример вывода этого кода:

---Start test with exception--- 
Time used: 3228ms, Number out of range: 49795 
---End test with exception--- 
---Start test without exception--- 
Time used: 3ms, Number out of range: 49795 
---End test without exception--- 
Смежные вопросы