Подтвердить что ты не робот

Делать исключения, уменьшают производительность?

Мое приложение проходит дерево каталогов и в каждом каталоге пытается открыть файл с определенным именем (используя File.OpenRead()). Если этот вызов вызывает FileNotFoundException, тогда он знает, что файл не существует. Предпочитаю ли я иметь вызов File.Exists() до этого, чтобы проверить, существует ли файл? Будет ли это более эффективным?

4b9b3361

Ответ 1

Это зависит!

Если у вас есть большая вероятность того, что файл будет там (вы знаете это для своего сценария, но в качестве примера примерно как desktop.ini) я предпочел бы прямо попытаться его открыть. В любом случае, в случае использования File.Exist вам нужно поместить File.OpenRead в try/catch для причин concurrency и избежать исключения во время выполнения, но это значительно повысит производительность вашего приложения, если вероятность того, что файл будет там, алгоритм страуса

Ответ 2

Обновление

Я запускал эти два метода в цикле и каждый раз:

void throwException()
{
    try
    {
        throw new NotImplementedException();
    }
    catch
    {
    }
}

void fileOpen()
{
    string filename = string.Format("does_not_exist_{0}.txt", random.Next());
    try
    {
        File.Open(filename, FileMode.Open);
    }
    catch
    {
    }
}

void fileExists()
{
    string filename = string.Format("does_not_exist_{0}.txt", random.Next());
    File.Exists(filename);
}

Random random = new Random();

Это результаты без приложенного отладчика и запуска сборки релиза:

Method          Iterations per second
throwException                  10100
fileOpen                         2200
fileExists                      11300

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

В случае, когда файл часто не присутствует, кажется, что быстрее проверить, существует ли файл. Я бы предположил, что в противном случае - когда файл обычно присутствует, вы обнаружите, что быстрее поймать исключение. Если производительность имеет решающее значение для вашего приложения, я предлагаю вам сравнить оба apporaches с реалистичными данными.

Как уже упоминалось в других ответах, помните, что даже если вы проверяете наличие файла перед его открытием, вы должны быть осторожны с состоянием гонки, если кто-то удалит файл после проверки вашего существования, но перед тем, как открыть его. Вам все равно нужно обработать исключение.

Ответ 3

Нет, не надо. Если вы используете File.Exists, вы вводите проблему concurrency. Если вы написали этот код:

if file exists then 
    open file

тогда если другая программа удалит файл между вами, когда вы проверили File.Exists и до того, как вы действительно откроете файл, программа по-прежнему будет генерировать исключение.

Во-вторых, даже если файл существует, это не значит, что вы действительно можете открыть файл, у вас может не быть разрешения на открытие файла, или файл может быть файловой системой только для чтения, поэтому вы не можете открыть ее режим записи и т.д.

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

EDIT: Бенчмаркинг Exception vs Existing in Python под Linux

import timeit
setup = 'import random, os'

s = '''
try:
    open('does not exist_%s.txt' % random.randint(0, 10000)).read()
except Exception:
    pass
'''
byException = timeit.Timer(stmt=s, setup=setup).timeit(1000000)

s = '''
fn = 'does not exists_%s.txt' % random.randint(0, 10000)
if os.path.exists(fn):
    open(fn).read()
'''
byExists = timeit.Timer(stmt=s, setup=setup).timeit(1000000)

print 'byException: ', byException   # byException:  23.2779269218
print 'byExists: ', byExists  # byExists:  22.4937438965

Ответ 4

Является ли это по-настоящему исключительным? Если это ожидается, вы должны тестировать с помощью оператора if и вообще не использовать исключения. Производительность - не единственная проблема с этим решением, и из-за того, что вы пытаетесь сделать, производительность не должна быть проблемой. Поэтому стиль и хороший подход должны быть предметом озабоченности этим решением.

Итак, чтобы подвести итог, так как вы ожидаете, что некоторые тесты потерпят неудачу, используйте File.Exists, чтобы проверить, а не ловить исключения после факта. Вы все равно должны поймать другие исключения, которые могут произойти, конечно.

Ответ 5

Не было бы наиболее эффективным запустить поиск в каталоге, найти его, а затем попытаться открыть его?

Dim Files() as string = System.IO.Directory.GetFiles("C:\", "SpecificName.txt", IO.SearchOption.AllDirectories)

Затем вы получите массив строк, который, как вы знаете, существует.

О, и в качестве ответа на исходный вопрос я бы сказал, что да, try/catch приведет к появлению большего количества циклов процессора, я бы также предположил, что IO peeks на самом деле занимает больше времени, чем накладные расходы процессорных циклов.

Запуск Exists сначала, а затем второй, это 2 IO-функции против 1 только попытки открыть его. Так что, действительно, я бы сказал, что общая производительность будет решением суда по времени процессора и скорости жесткого диска на ПК, на котором он будет работать. Если у вас есть более медленный процессор, я бы пошел с чеком, если у вас быстрый процессор, я могу пойти с try/catch на этом.

Ответ 6

File.Exists - хорошая первая линия защиты. Если файл не существует, то вы можете получить исключение, если попытаетесь его открыть. Проверка существования дешевле, чем стоимость броска и исключения. (Может быть, не намного дешевле, но немного.)

Еще одно соображение: отладка.. Когда вы работаете в отладчике, стоимость броска и обнаружения исключения выше, потому что в IDE есть крючки в механизм исключения, которые увеличивают ваш накладные расходы. И если вы проверили флажки "Разбить наброшенные" в "Отладки" > "Исключения", то любые исключаемые исключения станут огромной точкой боли. Только по этой причине я буду спорить о том, чтобы предотвратить исключения, когда это возможно.

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

Ответ 7

Я не знаю об эффективности, но я бы предпочел проверить File.Exists. Проблема в том, что это может произойти: плохой дескриптор файла и т.д. Если ваша программная логика знает, что иногда файл не существует, и вы хотите иметь другое поведение для существующих или несуществующих файлов, используйте File. Существует. Если его отсутствие существования совпадает с другими исключениями, связанными с файлами, просто используйте обработку исключений.

  • Vexing Exceptions - подробнее об использовании исключений хорошо

Ответ 8

Да, вы должны использовать File.Exists. Исключения должны использоваться для исключительных ситуаций, чтобы не контролировать нормальный поток вашей программы. В вашем случае файл, который не существует, не является исключительным случаем. Поэтому вы не должны полагаться на исключения.

ОБНОВЛЕНИЕ:

Поэтому каждый может попробовать это для себя, я отправлю свой тестовый код. Для не существующих файлов, полагаясь на File.Open, чтобы выбросить исключение для вас, примерно в 50 раз хуже, чем проверка с помощью File.Exists.

class Program
{
   static void Main(string[] args)
   {
      TimeSpan ts1 = TimeIt(OpenExistingFileWithCheck);

      TimeSpan ts2 = TimeIt(OpenExistingFileWithoutCheck);

      TimeSpan ts3 = TimeIt(OpenNonExistingFileWithCheck);

      TimeSpan ts4 = TimeIt(OpenNonExistingFileWithoutCheck);
   }

   private static TimeSpan TimeIt(Action action)
   {
      int loopSize = 10000;

      DateTime startTime = DateTime.Now;
      for (int i = 0; i < loopSize; i++)
      {
         action();
      }

      return DateTime.Now.Subtract(startTime);
   }

   private static void OpenExistingFileWithCheck()
   {
      string file = @"C:\temp\existingfile.txt";
      if (File.Exists(file))
      {
         using (FileStream fs = File.Open(file, FileMode.Open, FileAccess.Read))
         {
         }
      }
   }

   private static void OpenExistingFileWithoutCheck()
   {
      string file = @"C:\temp\existingfile.txt";
      using (FileStream fs = File.Open(file, FileMode.Open, FileAccess.Read))
      {
      }
   }

   private static void OpenNonExistingFileWithCheck()
   {
      string file = @"C:\temp\nonexistantfile.txt";
      if (File.Exists(file))
      {
         using (FileStream fs = File.Open(file, FileMode.Open, FileAccess.Read))
         {
         }
      }
   }

   private static void OpenNonExistingFileWithoutCheck()
   {
      try
      {
         string file = @"C:\temp\nonexistantfile.txt";
         using (FileStream fs = File.Open(file, FileMode.Open, FileAccess.Read))
         {
         }
      }
      catch (Exception ex)
      {
      }
   }
}

На моем компьютере:

  • ts1 =.75 секунд (то же самое с приложением отладчика или без него)
  • ts2 =.56 секунд (то же самое с приложением отладчика или без него)
  • ts3 =.14 секунд (то же самое с приложением отладчика или без него)
  • ts4 = 14,28 секунды (с прикрепленным отладчиком)
  • ts4 = 1.07 (без отладки)

ОБНОВЛЕНИЕ:

Я добавил подробности о том, был ли подключен dubgger или нет. Я тестировал сборку отладки и выпуска, но единственное, что имело значение, - это одна функция, которая в конечном итоге бросала исключения, пока отладчик был прикреплен (что имеет смысл). Тем не менее, проверка с помощью File.Exists - лучший выбор.

Ответ 9

Я бы сказал, что, вообще говоря, исключения "увеличивают" общую "производительность" вашей системы!

В вашем примере, в любом случае, лучше использовать File.Exists...

Ответ 10

Проблема с использованием File.Exists в первую очередь заключается в том, что он также открывает файл. Итак, вы дважды открываете файл. Я не оценил его, но, я думаю, это дополнительное открытие файла дороже, чем случайные исключения.

Если проверка File.Exists повышает производительность зависит от вероятности существующего файла. Если он существует, то не используйте File.Exists, если он обычно не существует, дополнительная проверка улучшит производительность.

Ответ 11

Накладные расходы на исключение заметны, но это не существенно по сравнению с файловыми операциями.