Подсказки по производительности C++ и эмпирические правила кто-либо?

Мое решение теперь выглядит так:

MATCH (start:LABEL)
WHERE id(start)= {}
MATCH (end:LABEL)
WHERE id(end) = {}
MATCH path=shortestPath((start)<-[:PATH*]-(end))
RETURN DISTINCT start

Это немного быстрее для меня.

7
задан Jon Seigel 27 April 2010 в 03:46
поделиться

25 ответов

Известная кавычка приходит на ум:

"Мы должны забыть о маленькой эффективности, сказать приблизительно 97% времени: преждевременная оптимизация является корнем всего зла". (Knuth, Donald. Структурное программирование с движением к Операторам, Журнал ACM, Вычисляя Обзоры, Vol 6, № 4, декабрь 1974. p.268.)

Но возможно Вы не должны передавать большие структуры данных значением так или иначе... :-)

Править: И, возможно, также избегайте O (N^2) или более сложные алгоритмы...

16
ответ дан 6 December 2019 в 04:44
поделиться

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

  • Попытайтесь выделить все свои объекты на запуске, минимизировать использование new в течение времени выполнения.
  • Разработайте свои структуры данных так, чтобы Ваши алгоритмы имели хороший выстрел в то, чтобы быть O (1).
  • И как обычно, постройте из модулей так, чтобы можно было сорвать и заменить позже. Это подразумевает, что у Вас есть всесторонний комплект модульных тестов, которые вселяют Вам веру, Ваше новое решение правильно.
  • Добавьте тесты производительности к своему комплекту модульного теста, чтобы удостовериться, что Вы непреднамеренно не заканчиваете с некоторым O (n*n) код :-)
0
ответ дан 6 December 2019 в 04:44
поделиться
  • Правило 1: не делать
  • Правило 2: мера
0
ответ дан 6 December 2019 в 04:44
поделиться

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

0
ответ дан 6 December 2019 в 04:44
поделиться

"преждевременная оптимизация является корнем всего зла" (Knuth, Donald)

Это действительно зависит от типа кода, который Вы пишете, и это - типичное использование.

0
ответ дан 6 December 2019 в 04:44
поделиться

не решая точную проблему, некоторый совет:

всегда кодируйте для интерфейсов (когда дело доходит до алгоритмов) так, чтобы можно было гладко заменить их эффективным один (любыми средствами req).

0
ответ дан 6 December 2019 в 04:44
поделиться

Из одной из книг C++ я относился (Эффективные Методы производительности C++ Bulka и Mayhew), который явно говорил об аспектах производительности C++. Один из них был;

при определении конструкторов.. инициализируйте других конструкторов также; некоторая вещь как;

class x {

x::x(char *str):m_x(str) {} // and not as x::x(char *str) { m_str(str); }

private:
std::string m_x;

};

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

1
ответ дан 6 December 2019 в 04:44
поделиться

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

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

Чтобы полностью понять преимущество однако, необходимо удостовериться, чтобы Вы не выставляли внутреннее проектное решение как часть интерфейса Вашего class/module/whatever. Ни один из Ваших клиентов не должен зависеть от Вашего использования a std::vector. По крайней мере обеспечьте определение типа, которое они (и Вы) могут использовать, который должен позволить вектору быть измененным на список (или безотносительно) в зависимости от Ваших потребностей.

Так же удостоверьтесь, что у Вас есть самый широкий выбор отлаженных алгоритмов и контейнеров в Вашем распоряжении. Повышение и/или TR1 являются prettymuch предметами первой необходимости в эти дни.

1
ответ дан 6 December 2019 в 04:44
поделиться

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

В значительной степени все остальное незначительно, по сравнению с ними.

1
ответ дан 6 December 2019 в 04:44
поделиться

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

1
ответ дан 6 December 2019 в 04:44
поделиться

Вот некоторые:

  • Эффективно Встраивание рычагов (в зависимости от Вашей платформы).

  • Избегайте использования временных файлов как можно больше (и знайте то, что они),

    x = y + z;

    Был бы лучше оптимизирован, если записано как:

    x=y;

    x + = z;

Кроме того, избегайте виртуальных функций и только создайте объекты, когда необходимо будет использовать их.

Если Вы находитесь в настроении, проверяете Эффективный C++. У меня есть копия дома от спины, когда я был в школе.

2
ответ дан 6 December 2019 в 04:44
поделиться

Две из лучших подсказок для C++:

Купите эффективный C++ Scott Meyers.

Затем купите Более эффективный C++ Scott Meyers.

3
ответ дан 6 December 2019 в 04:44
поделиться
  1. Всегда пытайтесь думать о том, как Ваша память смотрит - например, массив является последовательной строкой памяти размера numOfObjects X sizeof(object). двумерная матрица является n X m X sizeof(object) и каждый объект находится в индексе n + m X n и так

    for(int i = 0 ; i < n ; i++){
        for(int j = 0 ; j < m ; j++){
            arr[i,j] = f();
    

    намного лучше затем (на единственном процессе):

    for(int i = 0 ; i < n ; i++){
        for(int j = 0 ; j < m ; j++){
            arr[j,i] = f();
    

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

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

1
ответ дан 6 December 2019 в 04:44
поделиться

Рассмотрите использование пула памяти.

1
ответ дан 6 December 2019 в 04:44
поделиться

Викиучебник имеет некоторые вещи.

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

2
ответ дан 6 December 2019 в 04:44
поделиться

Сохраните свой код максимально чистым. Компиляторы ЧУДЕСНЫ в наше время. Затем если у Вас действительно есть проблема перфекта, профиль.

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

2
ответ дан 6 December 2019 в 04:44
поделиться

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

4
ответ дан 6 December 2019 в 04:44
поделиться

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

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

4
ответ дан 6 December 2019 в 04:44
поделиться

Используйте существующий, рассмотренный код, это использовалось и снова использовалось. (Пример: STL, повысьте по сравнению с прокруткой Ваших собственных контейнеров и алгоритмов),

Обновление из-за комментариев: ПРАВИЛЬНО используйте существующий, рассмотренный код, это использовалось и снова использовалось.

7
ответ дан 6 December 2019 в 04:44
поделиться

Не потрудитесь оптимизировать, пока это не будет необходимо. Узнать, необходимо ли это, профиль. Не угадывайте; имейте доказательство.

Кроме того, алгоритмическая оптимизация обычно оказывает большее влияние, чем микро. Используя A-звезду вместо новаторской грубой силы будет быстрее, точно так же, как как круги Bresenham лучше, чем использование sin/cos. Существуют исключения к ним, конечно, но они очень (очень) редки (<0,1%). Если у Вас есть хороший дизайн, изменение алгоритма изменяет только один модуль в Вашем коде. Легкий.

8
ответ дан 6 December 2019 в 04:44
поделиться
  • Когда возможное применение if или switch вместо вызовов через указатели функции. Разъяснение: void doit(int m) { switch(m) { case 1: f1(); break; case 2: f2(); break; } } вместо void doit(void(*m)()) { m(); } может встроить вызовы.
  • Когда возможный и не порождение вреда, предпочтите CRTP виртуальным функциям
  • Когда возможно, избегайте струн до и используйте Строковый класс. Это чаще всего будет быстрее. (постоянная продолжительность "мера", добавляя амортизировала постоянное время...),
  • Всегда передавайте определяемые пользователем введенные значения (кроме того, где это не имеет смысла. например, итераторы) в отношении константы (T const&) вместо того, чтобы копировать значение.
  • Для определяемых пользователем типов всегда предпочитайте ++t вместо t++
  • Использовать const рано, часто. Самый важный для улучшения удобочитаемости.
  • Попытайтесь сохранить new к минимуму. Всегда предпочитайте автоматические переменные (на стеке), если это возможно,
  • Вместо того, чтобы заполнить массивы самостоятельно, предпочтите инициализацию с пустым списком инициализатора как T t[N] = { }; если Вы хотите нули.
  • Используйте список инициализатора конструктора максимально часто, особенно при инициализации определяемых пользователем введенных участников.
  • Используйте функторы (типы с operator() перегруженный). Они встраивают лучше, чем вызовы через указатели функции.
  • Не используйте классы как std::vector или std::string если у Вас есть фиксированное размерное количество, не растущее. Использовать boost::array<T, Size> или явный массив и использование это правильно.

И действительно, я почти забыл это:

Преждевременная оптимизация является корнем всего зла

11
ответ дан 6 December 2019 в 04:44
поделиться

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

template <typename T>
struct add {
    operator T ()(T const& a, T const& b) const { return a + b; }
};

int result = add<int>()(1, 2);

Они могут использоваться почти в каждом контексте, где обычная функция или указатель функции могли использоваться. Они обычно происходят из также std::unary_function или std::binary_function но это часто не необходимо (и на самом деле только сделанный для наследования некоторых полезных typedefs).

ОТРЕДАКТИРУЙТЕ явное <int> квалификация типа необходима в вышеупомянутом коде. Вывод типа только работает на вызовы функции, не, например, создание. Однако это может часто опускаться путем использования a make функция помощника. Это сделано в STL для pairs:

template <typename T1, typename T2>
pair<T1, T2> make_pair(T1 const& first, T2 const& second) {
    return pair<T1, T2>(first, second);
}

// Implied types:
pair<int, float> pif = make_pair(1, 1.0f);

Кто-то упомянул в комментариях, что функторы иногда называют “functionoids”. Yesish – но не совсем. На самом деле “функтор” является (несколько странным) сокращением для “функционального объекта”. functionoid концептуально подобен, но понят путем использования виртуальных функций (хотя они иногда используются синонимично). Например, functionoid мог быть похожим на это (наряду с его необходимым интерфейсным определением):

template <typename T, typename R>
struct UnaryFunctionoid {
    virtual R invoke(T const& value) const = 0;
};

struct IsEvenFunction : UnaryFunctionoid<int, bool> {
    bool invoke(int const& value) const { return value % 2 == 0; }
};

// call it, somewhat clumsily:
UnaryFunctionoid const& f = IsEvenFunction();
f.invoke(4); // true

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

FAQ C++ имеет больше для высказывания относительно этого предмета.

11
ответ дан 6 December 2019 в 04:44
поделиться

Подсказка по производительности числа № 1 должна представить Ваш код рано и часто. Существует много общих, "не делают этого" подсказки, но действительно трудно гарантировать, что это повлияет на производительность Вашего приложения. Почему? Каждое приложение отличается. Легко сказать, что передача вектора значением плоха, если у Вас есть много элементов, но Ваша программа даже использует вектор (Вы, вероятно, должны, но...)?

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

Править:

Несколько человек прокомментировали "раннюю" часть моего ответа. Я не думаю, что необходимо быть профильными со дня 1. Однако Вы не должны также ожидать до 1 месяца от поставки также.

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

На типичном проекте я нахожу, что у меня есть код, встречающий это criterias 30%-40% пути через проект (100%, находящихся в клиентских руках). Я свободно классифицирую на этот раз как рано.

12
ответ дан 6 December 2019 в 04:44
поделиться

Используя универсальные алгоритмы большая подсказка по оптимизации - не с точки зрения времени выполнения, а кодирования времени. Знание, что можно отсортировать (запускаются, конец) и ожидает диапазон - быть им, два указателя или итераторы к базе данных - будут отсортированы (и кроме того, используемый алгоритм будет временем выполнения, эффективным также). Универсальное программирование - то, что делает C++ уникальным и мощным, и необходимо всегда иметь в виду его. Вам не придется записать много алгоритмов, потому что версии уже существуют (и вероятны как быстро или быстрее, чем что-нибудь, что Вы записали бы). Если у Вас есть другие соображения, то можно специализировать алгоритмы.

2
ответ дан 6 December 2019 в 04:44
поделиться

Select best performing algorithms, use less memory, use less branching, use fast operations, use small number of iterations.

0
ответ дан 6 December 2019 в 04:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: