Когда вычисление или чтение переменных быстрее? - PullRequest
2 голосов
/ 16 марта 2010

Если честно, я не совсем знаю, что делают "маленькие зеленые человечки" в моем процессоре и компиляторе, поэтому мне иногда хотелось бы знать:).

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

Я думаю, что это зависит от того, насколько "сложным" и "длинным" является вычисление, и насколько быстрым является кеш, где хранятся переменные, но я не имею ни малейшего понятия, что быстрее:).

Спасибо за любой ответ на мой крошечный, но важный вопрос!

Andreas

PS: возможно, важно знать, что я кодирую в JAVA, но это скорее общий вопрос.

Ответы [ 8 ]

9 голосов
/ 16 марта 2010

Обычно всегда будет быстрее хранить что-то рассчитанное один раз, а не вычислять его каждый раз.

Но в зависимости от сложности расчета это может не иметь значения. Например, если вы хотите вычислить сумму 3, 2 и 1, увеличение скорости от вычисления ее один раз и вычисления каждый раз будет минимальным и не стоит хлопот, если вы не делаете это миллионы раз.

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

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

3 голосов
/ 16 марта 2010

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

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

1 голос
/ 16 марта 2010

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

Кроме того, общий совет - писать clear код и беспокоиться о таких низкоуровневых оптимизациях только тогда, когда:

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

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

1 голос
/ 16 марта 2010

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

1 голос
/ 16 марта 2010

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

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

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

1 голос
/ 16 марта 2010

Реального ответа на этот вопрос нет. Хранить вещи в кеше быстрее, если доступ к кешу происходит быстрее, чем вычисление. Вычислять вещи быстрее, если доступ к кешу медленнее, чем ваш расчет.

Как и на все вопросы «что быстрее», ответом будет профиль, затем профиль снова и затем профиль снова. Ваш расчет действительно является узким местом, или вы где-то ждете ввода-вывода? Попробуйте вещи и увидите!

0 голосов
/ 16 марта 2010

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

public class Rectangle
    private int _height;
    public int getHeight() {
        return _height;
    }
    public void setHeight(int value) {
        _height = value;
    }

    private int _width;
    public int getWidth() {
        return _width;
    }
    public void setWidth(int value) {
        _width = value;
    }

    private int _area;
    public int getArea() {
        if (_area == 0) {
            _area = _width * height;
        }
        return _area;
    }
}

Здесь вычисление площади сохраняется, поэтому его не нужно пересчитывать (это немного тривиальный пример, и умножения на самом деле не являются достаточно дорогостоящими, чтобы оправдать кэширование, но вы получаете дрейф.). Следующий код работает нормально:

Rectangle r = new Rectangle();
r.setHeight(5);
r.setWidth(5);

r.getArea(); // returns 25.

Но если мы изменим какую-либо информацию, используемую для вычисления кэшированного элемента, в коде будет ошибка:

r.setHeight(3);
r.getArea(); // returns 25 - should be 15!

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

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

0 голосов
/ 16 марта 2010

Я бы сказал, вычисляя его один раз и сохраняя в нем.

В приведенном выше примере вы не склонны постоянно добавлять статические значения вместе. Значения, которые вы будете вычислять, скорее всего, будут другими переменными, хранящимися в памяти / на диске.

Так что, если вы

  1. собрать все ваши переменные
  2. рассчитать результат
  3. сохранить в памяти

С этого момента вам нужно будет только извлечь значение, а не повторять шаги 1 и 2.

...