2010-06-28 2 views
0

Я разрабатываю классы для своего приложения (сетевой инструмент). I этот базовый класс:Оптимизация кода на С ++

class Descriptor 
{ 
    // ... 

    public: 
     virtual void data_read (void); 
     virtual void data_write (void); 
     virtual void data_error (void); 

    protected: 
     int socket_descriptor; 
    // ... 
} 

class TcpClient : 
    public Descriptor 
{ 
    // ... 
} 

Многие классы основаны на дескрипторе. Я отслеживаю события сокетов с помощью epoll. Когда я хочу, чтобы посмотреть события на объекте TcpClient добавить сокет и указатель объекта для этого объекта Epoll, код:

epoll_event descriptor_events; 

descriptor_events.events = EPOLLIN; 
descriptor_events.data.fd = this->socket_descriptor; 
descriptor_events.data.ptr = this; 

epoll_ctl (epoll_descriptor, EPOLL_CTL_ADD, this->socket_descriptor, &descriptor_events); 

рассылает Epoll событие в отдельном потоке таким образом:

Descriptor *descriptor (NULL); 

// ... 

return_value = epoll_wait (epoll_descriptor, events, 64, -1); 

while (i < return_value) 
{ 
    descriptor = (Descriptor *) (events [i]).data.ptr; 

    if ((events [i]).events & EPOLLOUT) 
     descriptor->data_write(); 
    if ((events [i]).events & EPOLLIN) 
     descriptor->data_read(); 
    if ((events [i]).events & EPOLLERR) 
     descriptor->data_error(); 

    i++; 
} 

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

Я также думаю о двух других реализаций (однако я не уверен, если the're гораздо быстрее):

typedef void (*function) (Descriptor *) EventFunction; 

class Descriptor 
{ 
    // ... 

    public: 
     EventFunction data_read; 
     EventFunction data_write; 
     EventFunction data_error; 

    protected: 
     Descriptor (EventFunction data_read, 
        EventFunction data_write, 
        EventFunction data_error); 

     int socket_descriptor; 
    // ... 
} 

или использовать CRTP.

Возможно, у вас есть другие идеи по реализации этого?

ответ

2

Если не доказано иное, ваш оригинальный дизайн выглядит хорошо для меня.

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

(у меня есть один комментарий о классе Descriptor:. Если вы не планируете иметь общий data_read(), data_write(), и data_error() методы, которые я рекомендовал бы сделать их чисто виртуальные методы)

+0

Как насчет CRTP? Это немного уродливое, но не должно содержать никаких накладных расходов во время выполнения. – Goofy

+1

Если CRTP - это вариант, не стесняйтесь идти на это. Но для низкоуровневого ввода-вывода сокетов центральный процессор не часто является узким местом. Скорее всего, это не имеет никакого значения, потому что вы просто не отправляете/не получаете столько пакетов в секунду. – jalf

+0

+1 к jalf. Эффективный низкоуровневый ввод/вывод сокета обычно сводится к чрезвычайно жесткому и эффективному использованию потоков. Для некоторых операционных систем написание наиболее масштабируемых серверов требует даже программирования на уровне ядра! В Windows у нас есть порты завершения ввода-вывода. – stinky472

0

Под зонтиком don't reinvent the wheel я бы предложил посмотреть на Boost.Asio, так как он предлагает большую часть функциональности, описанную в вашем примере кода.

1

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

+0

Ну, я хочу изобрести колесо (я студент по информатике), и я хочу просто попытаться написать такие вещи самостоятельно, чтобы улучшить навыки и расширить знания. Более того, я собираюсь играть с протоколом SCTP, поэтому Boost.Asio может не соответствовать моим требованиям. – Goofy

+2

@Goofy: If Boost.Asio не соответствует вашим требованиям SCTP, возможно, было бы полезно расширить его и внести свои улучшения в сообщество Boost. Таким образом, вы могли бы улучшить свои собственные навыки и позволить другим использовать ваши результаты. – Void

+0

@Goofy: Ну, в таком случае, заново изобрести! Отличный выбор областей. Я согласен с Void в том, что адаптация Boost для поддержки SCTP - это идея, которую стоит рассмотреть. Если вы не являетесь экспертом в C++, когда начинаете, вы почти наверняка будете к тому времени, когда вы закончите ;-) – Rakis

Смежные вопросы