C ++: борьба с полиморфизмом - PullRequest
8 голосов
/ 06 ноября 2010

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

Много раз данная виртуальная функция вызывается для одного и того же объекта снова и снова;Я знаю, что тип объекта не меняется, и в большинстве случаев компилятор может легко вывести, что хорошо:

BaseType &obj = ...;
while( looping )
    obj.f(); // BaseType::f is virtual

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

BaseType &obj = ...;
FinalType &fo = dynamic_cast< FinalType& >( obj );
while( looping )
    fo.f(); // FinalType::f is not virtual

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

Идея верхнего приведения (как показано во втором фрагменте) не выглядит мне так хорошо: BaseType может быть унаследовано многими классами, и попытка привести к верхнему приведению ко всем из них будет довольно распространенной.

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

, есть ли лучший метод?

Редактировать: Ну, конечно, это не так сильно повлияет.Этот вопрос главным образом состоял в том, чтобы узнать, было ли что-то делать, так как похоже, что эти накладные расходы предоставляются бесплатно (эти накладные расходы, по-видимому, очень легко убить). Я не понимаю, почему бы и нет.легкое ключевое слово для небольших оптимизаций, таких как C99 restrict, чтобы сказать компилятору, что полиморфный объект имеет фиксированный тип, - это то, на что я надеялся.,Посмотрите на этот ad-hoc extreme код:

struct Base { virtual void f(){} };
struct Final : public Base { void f(){} };

int main( ) {
    Final final;
    Final &f = final;
    Base &b = f;

    for( int i = 0; i < 1024*1024*1024; ++ i )
#ifdef BASE
        b.f( );
#else
        f.f( );
#endif

    return 0;
}

Компиляция и запуск, время:

$ for OPT in {"",-O0,-O1,-O2,-O3,-Os}; do
    for DEF in {BASE,FINAL}; do
        g++ $OPT -D$DEF -o virt virt.cpp &&
        TIME="$DEF $OPT: %U" time ./virt;
    done;
  done           
BASE : 5.19                                                                                                                                                                         
FINAL : 4.21                                                                                                                                                                        
BASE -O0: 5.22                                                                                                                                                                      
FINAL -O0: 4.19                                                                                                                                                                     
BASE -O1: 3.55                                                                                                                                                                      
FINAL -O1: 1.53                                                                                                                                                                     
BASE -O2: 3.61                                                                                                                                                                      
FINAL -O2: 0.00                                                                                                                                                                     
BASE -O3: 3.58                                                                                                                                                                      
FINAL -O3: 0.00                                                                                                                                                                     
BASE -Os: 6.14                                                                                                                                                                      
FINAL -Os: 0.00

Я думаю, только -O2, -O3 и-Оы встраивают Final::f.

И эти тесты были проведены на моей машине с новейшим GCC и двухъядерным процессором AMD Athlon (tm) 64 X2 4000+.Я думаю, это может быть намного медленнее на более дешевой платформе.

Ответы [ 2 ]

8 голосов
/ 06 ноября 2010

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

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

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

2 голосов
/ 06 ноября 2010

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

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

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