Вызывает ли boost :: bind накладные расходы? - PullRequest
5 голосов
/ 05 мая 2011

Я сейчас работаю над сетевым программным обеспечением. У него есть один основной класс, server, который явно представляет экземпляр сервера.

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

Код похож на:

class server
{
  public:
    typedef boost::function<void (int duration)> callback_func;

    void send_request(endpoint& ep, callback_func cb);
};

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

void mycallback(const server& sv, int duration) { ... }

server sv;
sv.send_request("localhost", boost::bind(&mycallback, boost::ref(sv), _1));

Но мне интересно: есть ли накладные расходы, делающие это? Будут ли звонки на mycallback медленнее, чем при использовании «обычного» звонка?

Спасибо.

Примечание для ноги: Конечно, я мог бы изменить typedef на: typedef boost::function<void (const server& sv, int duration)> callback_func;, и если boost::bind вызовет какие-либо существенные накладные расходы, то, вероятно, я буду делать в конце. Я просто хотел бы знать, какие расходы подразумевают использование boost::bind.

Ответы [ 4 ]

5 голосов
/ 05 мая 2011

boost::bind генерирует функциональный объект, который можно оптимизировать, если он используется в качестве аргумента для шаблонов функций, но boost::function предотвращает эту оптимизацию, так же как передача указателя на функцию предотвращает ее встраивание. boost::function само по себе не должно вводить больше служебной информации, чем виртуальная функция all или вызываться через указатель на функцию.

PS. Я согласен с Тамашем Селеи: сделайте 10 миллионов запросов и оцените его.

5 голосов
/ 05 мая 2011

Конечно, это вызывает накладные расходы. Он создает функтор, который хранит связанные параметры и имеет operator(), который вы вызываете с остальными аргументами. Теперь, это важно? Я не знаю, потому что это просто слово. Сделайте 10 миллионов запросов и оцените их. Вы единственный, кто может сказать, важны ли эти накладные расходы для вас.

Также я столкнулся с подобной проблемой. Так как мне действительно не нужны были делегаты, я мог сойти с рук с указателями на функции. Но я нашел интересный бенчмарк , в котором также упоминается некоторая альтернативная реализация, причем все они имеют лучшую производительность, чем boost::function. Это происходит за счет переносимости и, в некоторых случаях, некрасивых нестандартных взломов в реализации (но взамен действительно хорошей производительности).

2 голосов
/ 06 мая 2011

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

Первое косвенное обращение связано с стиранием типа, которое происходит в boost :: function (это задокументировано в документации boost::function). Этот вариант не может быть оптимизирован, и вы получите то же наказание и с пустым указателем на функцию.

Вторая косвенность возникает при вызове функции mycallback через указатель на функцию. Очень хорошо оптимизирующий компилятор может понять это и оптимизировать это, но обычный компилятор не сможет. Вы можете избавиться от этой косвенности (во всех компиляторах), если превратить mycallback в функциональный объект:

Вместо

void mycallback( .1. ) { .2. }

вы делаете

struct mycallback {
    void operator()( .1. ) const { .2. }
};
1 голос
/ 05 июля 2012

Имейте в виду, что boost :: bind вызывает копию функтора. Это может быть очень значительным. Для моей операционной системы новости и удаления очень дороги. См. Документацию boost :: bind о ref () и cref (). Я считаю, что функции-члены также вызывают копии функторов, но документации по этому поводу нет.

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