|
Программирование >> Оптимизация возвращаемого значения
по функциям библиотеки имеют совершенно различные характеристики производительности. Например, рассмотрим библиотеки ввода-вывода iostream и stdio, доступные во всех компиляторах языка С++. Библиотека iostream имеет ряд преиму-шеств перед аналогичной библиотекой языка С. Например, она является расширяемой и более безопасной. Что же касается эффективности, библиотека iostream обычно проигрывает библиотеке stdio, и исполняемые файлы, созданные при помоши stdio, обычно имеют меньший размер и работают быстрее. Проанализируем вначале скорость выполнения. Оценить различие в производительности между этими библиотеками можно, выполнив тесты для каждой из них. При этом надо иметь в виду, что все тесты производительности врут . Сложно не только определить набор входных данных, соответствующий типичному применению программы или библиотеки, но и выяснить, насколько типичными являются ваши задачи или задачи ваших пользователей. Тем не менее, тестовые приложения могут дать некоторое понятие о сравнительной производительности различных походов к задаче, поэтому хотя и глупо полностью полагаться на них, игнорировать их также неразумно. Рассмотрим простую тестовую программу, выполняющую только основные функции ввода-вывода. Эта программа считывает из стандартного ввода 30.000 чисел с плавающей точкой и записывает их стандартный вывод в формате с фиксированным числом знаков после запятой. Выбор между библиотеками iostream и stdio осуществляется во время компиляции и зависит от переменной препроцессора STDIO. Если она определена, то используется библиотека stdio, в противном cnjiae применяется библиотека iostream. #ifdef STDIO #include <stdio.h> #else #include <iostream> #include <iomanip> using namespace std; #endif const int VALUES =30000; Число повторений цикла. int main() double d; for (int n = 1; n <= VALUES; ++n) { #ifdef STDIO scanf( %lf , &d); printf{ %10.5f , d); #else cin >> d; cout << setwdO) Задать ширину поля. setprecision{5) Знаков после запятой. << setiosf lags (ios : : showpoint) Дополнить нулями. setiosflags(ios::fixed) Использовать эти значения. d; #endif if (n % 5 == 0) { #ifdef STDIO printf{ \n ); #else cout \n ; #endif return 0; } Когда на вход программы попадают натуральные логарифмы положительных чисел, на ее выходе пол5ится: 0.00000 0.69315 1.09861 1.38629 1.60944 1.79176 1.94591 2.07944 2.19722 2.30259 2.39790 2.48491 2.56495 2.63906 2.70805 2.77259 2.83321 2.89037 2.94444 2.99573 3.04452 3.09104 3.13549 3.17805 3.21888 Это по крайней мере демонстрирует, что при помощи библиотеки iostream можно выводить числа в формате с фиксированным числом знаков после запятой. Конечно же, запись cout setw(10) setprecision(5) setiosflags(ios::showpoint) setiosflags(ios::fixed) d; совсем не так проста, как printf( %10.5f , d); но operator является расширяемым и обеспечивает безопасность при работе с различными типами, а функция printf - нет. Я запускал эту программу на разных компьютерах, под разными операционными системами и использовал разные компиляторы, и во всех случаях версия на основе библиотеки stdio была быстрее. Иногда лишь немного (примерно на 20%), иногда значительно (почти на 200%), но никогда реализация на основе библиотеки iostream не могла сравниться по скорости с соответствующей реализацией на основе библиотеки stdio. Кроме того, обычно размер исполняемого файла этой простой программы, скомпилированной с использованием библиотеки stdio, был меньше (иногда намного меньше), чем размер соответствующего исполняемого файла при использовании библиотеки iostream. (Для реальных программ это различие обычно не является столь существенным.) Степень преимущества библиотеки stdio сильно зависит от способа ее реализации, поэтому в будущих версиях тестировавшихся систем или в каких-либо других системах разница в производительности между этими двумя библиотеками может быть пренебрежимо мала. Может существовать реализация библиотеки iostream, которая быстрее, чем библиотека stdio, так как типы операндов в библиотеке iostream определяются во время компиляции, а функции библиотеки stdio обычно обрабатывают строку формата во время выполнения программы. Различие между производительностью этих двух библиотек не столь важно, и рассматривается только в качестве примера. Основная мысль вышеизложенного заключается в том, что разные библиотеки с аналогичной функциональностью часто обладают различной производительностью, поэтому после определения узких мест программы (при помощи отладчика - см. правило 16), вы увидите, удастся ли избавиться от них, заменив одну библиотеку на другую. Например, если узким местом программы является скорость ввода-вывода, можно попробовать заменить библиотеку iostreams на stdio, если же значительная часть времени тратится на выделение и освобождение памяти, попытайтесь использовать различные реализации operator new и operator delete (см. правило 8). Так как разные библиотеки демонстрируют различные подходы к эффективности, расширяемости, переносимости, типовой безопасности и другим вопросам, то иногда можно повысить эффективность программного обеспечения, использовав библиотеку, разработчики которой уделили больше внимания вопросам производительности. Правило 24. Учитывайте затраты, связанные с виртуальными функциями, множественным наследованием, виртуальными базовыми классами и RTTI Компиляторы С++ должны реализовывать все функции языка. Детали реализации, конечно же, зависят от конкретного компилятора, и разные компиляторы по-разному реализуют те или иные свойства языка. В большинстве случаев вам не придется заботиться об этих различиях. Но иногда реализация некоторых свойств языка заметно влияет на размер объектов и скорость, с которой выполняются функции-члены, поэтому вам важно иметь общее представление о том, что происходит за сценой . В качестве примера можно в первую очередь привести виртуальные функции. При вызове виртуальной функции выполняемый код должен соответствовать динамическому типу объекта, для которого вызывается функция; независимо от типа указателя или ссылки на объект. Как без лишних затрат обеспечить такое поведение в компиляторе? Большинство реализаций используют виртуальные таблицы (virtual table, сокращенно vtbl) и указатели на виртуальные таблицы (virtual table pointer, сокращенно vptr). Виртуальная таблица обычно является массивом указателей на функции. (Некоторые компиляторы используют вместо массива разновидность связного списка, но принцип действия остается тем же самым.) Каждый класс программы.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |