Производительность переопределения против оператора if - PullRequest
4 голосов
/ 31 октября 2011

Я расширяю и улучшаю Java-приложение , которое также выполняет длительный поиск с небольшим DSL (в деталях оно используется для Нахождения модели, да, в общем, NP-Complete).

Во время этого поиска я хочу показать небольшой индикатор выполнения на консоли.Из-за общей структуры DSL я не могу рассчитать общий размер пространства поиска.Поэтому я могу только вывести ход выполнения первого оператора «backtracking».

Теперь вопрос: я могу использовать флаг для каждого оператора backtracking, чтобы указать, что этот оператор должен сообщать о прогрессе.При оценке оператора я могу проверить флаг с помощью оператора if:

public class EvalStatement {
  boolean reportProgress;

  public EvalStatement(boolean report) {
     reportProgress = report;
  }

  public void evaluate() {
    int progress = 0;

    while(someCondition) {
      // do something

      // maybe call other statement (tree structure)

      if (reportProgress) {
         // This is only executed by the root node, i. e.,
         // the condition is only true for about 30 times whereas
         // it is false millions or billions of times
         ++progress;
         reportProgress(progress);
      }
    }
  }
}

Я также могу использовать два разных класса:

  • Класс, который ничего не делает
  • Подкласс, который выполняет вывод

Это будет выглядеть так:

public class EvalStatement {
  private ProgressWriter out;
  public EvalStatement(boolean report) {
      if (report)
        out = new ProgressWriterOut();
      else
        out = ProgressWriter.instance;     
  }
  public void evaluate() {
    while(someCondition) {
      // do something
      // maybe call other statement (tree structure)
      out.reportProgress(progress);
    }
  }
}

public class ProgressWriter {
  public static ProgressWriter instance = new ProgressWriter();
  public void reportProgress(int progress) {}
}

public class ProgressWriterOut extends ProgressWriter {
  int progress = 0;
  public void reportProgress(int progress) {
    // This is only executed by the root node, i. e.,
    // the condition is only true for about 30 times whereas
    // it is false millions or billions of times
    ++progress;
    // Put progress anywhere, e. g., 
    System.out.print('#');
  }
}

Теперь действительно вопрос (ы):

  • Является ли Java-поиск метода для вызова быстрее, чем оператор if?
  • Кроме того, будет ли интерфейс и два независимых класса быстрее?

Я знаю, что Log4J рекомендует поставитьоператор if вокруг log-вызовов, но я думаю, что основной причиной является построение параметров, особенно строк.У меня есть только примитивные типы.

EDIT : Я немного пояснил код (то, что часто называют ... использование синглтона здесь не имеет значения).

Кроме того, я сделал два долгосрочных прогона поиска, в которых оператор if, соответственно, вызов операции был обработан 1.840.306.311 раз на машине, не делающей ничего другого:

  • Версия if заняла10 ч. 6 мин. 13 сек. (50,343 "ударов" в секунду)
  • Версия or заняла 10 ч 9 мин 15сек (50,595 "ударов" в секунду)

Я бы сказал, это не такдать реальный ответ, потому что разница в 0,5% заключается в погрешности измерения.

Мой вывод: они более или менее ведут себя одинаково, но основной подход может быть более быстрым в долгосрочной перспективе, как и предполагалКейн в ответах.

Ответы [ 5 ]

5 голосов
/ 31 октября 2011

Я думаю, что это определение чрезмерной оптимизации в учебнике.Вы даже не уверены, что у вас проблемы с производительностью.Если вы не делаете МИЛЛИОНЫ звонков через этот раздел, он даже не будет отображаться в ваших отчетах о горячих точках, если вы его профилировали.Если операторы и вызовы методов имеют порядок выполнения наносекунд.Таким образом, для разницы между ними вы говорите о том, чтобы максимально сэкономить 1-10 нс.Чтобы человек воспринимался как медленный, он должен быть порядка 100 миллисекунд, и это если пользователь даже обращает внимание, например, активно нажимает и т. Д. Если он наблюдает за индикатором прогресса, он недаже заметив это.

Скажем, мы хотели посмотреть, добавит ли это дополнительное время хотя бы на 1 с, и вы обнаружили, что один из них может сэкономить 10 нс (это, вероятно, похоже на экономию 1-4 нс).Это значит, что вам нужно будет вызывать этот раздел 100 000 000 раз, чтобы сэкономить 1 с.И я могу гарантировать, что если у вас будет 100 миллионов звонков, вы найдете 10 других областей, которые стоят дороже, чем выбор if или полиморфизм там.Кажется глупым спорить о достоинствах 10 нс, если у вас есть шанс сэкономить 1 с, не так ли?

Я бы больше беспокоился о том, что вы используете синглтон, чем производительность.

2 голосов
/ 31 октября 2011

Я бы не беспокоился об этом - стоимость очень мала, вывод на экран или вычисления будут намного медленнее.

1 голос
/ 31 октября 2011

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

Тем не менее, если бы мне пришлось угадывать, я бы сказал следующее:

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

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

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

1 голос
/ 31 октября 2011

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

1 голос
/ 31 октября 2011

Я бы предположил, что поиск метода быстрее, чем оценка if (). Фактически, также версия с if нуждается в поиске метода. И если вы действительно хотите выжать каждый бит производительности, используйте закрытые финальные методы в ваших ProgessWriter, поскольку это может позволить JVM встроить метод, чтобы не было поиска метода, и даже не вызов метода машинный код, полученный из байтового кода после его окончательной компиляции.

Но, возможно, они оба довольно близки по производительности. Я бы предложил протестировать / профиль, а затем сосредоточиться на реальных проблемах производительности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...