Как написать более эффективный код - PullRequest
3 голосов
/ 27 августа 2010

Вопрос века? Я в основном хочу знать, что было бы более эффективно, если бы я написал этот код в виде нескольких разных переменных или если бы использовал маленькие массивы.

int x = 34;
int y = 28;
int z = 293;

против

double coordinate[3] = {34, 28, 293};

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

typedef struct coordinates_t {
    double x = 0.0;
    double y = 0.0;
    double z = 0.0;

} coordinates;


typedef struct car_t {
    coordinates start; // car starting point
    coordinates location; // car current Location
    coordinates targCarVector; // Vector to car from target
    coordinates altitude; // Altitude of car
    coordinates distance; // Distance from car start to current position
} car;

Мне нужно будет сделать что-то вроде:

distance = car1.location - car1.start;

Если я не использую массив, у меня будет много строк кода, но если я буду использовать массив, мне придется использовать циклы. Являются ли массивы и циклы более интенсивной памятью / процессором? Я в основном пытаюсь понять, какой способ написания кода наиболее эффективен.

Спасибо, DemiSheep

Ответы [ 12 ]

21 голосов
/ 27 августа 2010

Эффективность важнее ремонтопригодности и читабельности? Ответ - нет. Даже если у вас есть приложение, критичное ко времени, вы будете тратить 90% времени на менее чем 10% кода, и поэтому только 10% необходимо кодировать максимально эффективно.

Если вы не измерили и не обнаружили, какой из 10% является виновником, вы почти наверняка будете оптимизировать код, который в первую очередь не требует много времени выполнения. Это пустая трата времени.

9 голосов
/ 27 августа 2010

Первый вопрос: Хотите оптимизировать его? Скорее всего, вы не хотите. По крайней мере, если вы «всегда пишете код, как будто парень, который в конечном итоге будет поддерживать ваш код, будет жестоким психопатом, который знает, где вы живете». Читаемость, ясность намерений и удобство обслуживания всегда на первом месте.

Второй вопрос: Стоит ли оптимизировать ? По словам Дональда Кнута, в 97% это не так, и вы не спрашиваете Кнута, не так ли? Другим распространенным эмпирическим правилом является правило 80/20, т. Е. 80% времени выполнения тратится на 20% кода. Если вы вообще оптимизируете, сначала узнайте, где оптимизировать. Если ты угадаешь, ты ошибаешься. Период.

Третий вопрос: МОЖЕТЕ ли вы оптимизировать его? Нет, не можете, по крайней мере, не так легко. Вы думаете, что вы умнее, чем сотни программистов, которые писали ваш компилятор на протяжении многих десятилетий? Это не так. Если реальная реализация вашего алгоритма и структур данных может быть оптимизирована, вы можете предположить, что ваш компилятор может сделать это самостоятельно. Компилятор может выполнять развертывание цикла, переупорядочение команд, комбинирование переменных с неперекрывающимся временем жизни, оптимизацию структуры и многое другое - и в эту эпоху это даже лучше, чем большинство программистов на ассемблере в большинстве случаев. И даже если есть небольшой потенциал, вам лучше сосредоточиться на реализации лучшего алгоритма. Ни один компилятор не может превратить O (n ^ 2) в O (n log n), но, возможно, умный ученый сделал это, и вы можете реализовать его алгоритм, чтобы получить гораздо лучшую производительность, чем любая микрооптимизация.

7 голосов
/ 27 августа 2010

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

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

Повышение скорости простой для понимания кодовой базы намного проще, чем понимание кодовой базы, которая пронизана преждевременной и ненужной «оптимизацией».

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

3 голосов
/ 27 августа 2010

Если вы действительно хотите микрооптимизировать это, используйте возможности инструкций SIMD вашего ЦП. Если вы используете платформу x86, вы можете использовать инструкции MMX или SSE для векторной арифметики вместо того, чтобы добавлять каждую часть координаты индивидуально (ваш компилятор может не генерировать их без специальной команды выключатели или встроенная сборка). Это, вероятно, приведет к большему ускорению, чем переключение между отдельными переменными и массивом. Я говорю «вероятно», потому что нет способа сказать наверняка, не испробовав оба способа и не измерив время выполнения.

2 голосов
/ 27 августа 2010

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

for (i = 0; i < 3; ++i) {
    c[i] = a[i] - b[i];
}

на:

c[0] = a[0] - b[0];
c[1] = a[1] - b[1];
c[2] = a[2] - b[2];

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

Нет простого ответа на вопрос «какой из них будет быстрее?», но если бы вы были уверены, что с максимальной оптимизацией ваш компилятор будет использовать его.

2 голосов
/ 27 августа 2010

Используйте массив, скомпилируйте с -funroll-loops.Вы получаете преимущества обоих.

1 голос
/ 30 августа 2010

Ответ века

Не ставь телегу перед лошадью.

Другими словами, сначала профиль.

Все это «знают», но большая категория вопросов по SO имеет вид «Что быстрее, X или Y?»

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

1 голос
/ 27 августа 2010

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

В порядке убывания важности код должен быть

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

Где-то после этого вы можете начать беспокоиться о производительности.

0 голосов
/ 20 августа 2016

Я обычно не беспокоюсь об эффективности ...

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

На самом деле немного быстрее.

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

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

0 голосов
/ 27 августа 2010

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

Некоторые инструменты для этого доступны с открытым исходным кодом, например gprof .

...