Вызывает ли boost::bind накладные расходы?
Вопрос
В настоящее время я работаю над сетевым программным обеспечением.У него есть один основной класс, server
который, очевидно, представляет собой экземпляр сервера.
A 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
.
Решение
Конечно, это приводит к накладным расходам.Что он делает, так это то, что он создает функтор, который хранит связанные параметры и имеет operator()
который вы вызываете с оставшимися аргументами.Итак, имеет ли это значение?Я не знаю, потому что это всего лишь слово.Сделайте 10 миллионов запросов и измерьте это.Вы единственный, кто может сказать, значимы ли для вас эти накладные расходы или нет.
Кроме того, я столкнулся с аналогичной проблемой.Поскольку на самом деле мне не нужны были делегаты, я мог обойтись указателями на функции.Но я нашел интересную эталонный показатель в котором также упоминаются некоторые альтернативные реализации, все они с лучшей производительностью, чем boost::function
.Это достигается ценой переносимости и в некоторых случаях некрасивых, нестандартных взломов в реализации (но взамен вы получаете действительно хорошую производительность).
Другие советы
boost::bind
генерирует функциональный объект, который может быть оптимизирован, если он используется в качестве аргумента для шаблонов функций, но boost::function
предотвращает эту оптимизацию, точно так же, как передача указателя на функцию предотвратит ее встраивание. boost::function
само по себе не должно приводить к большим накладным расходам, чем виртуальная функция all или вызов через указатель на функцию.
PS.Я согласен с Тамашем Селеем:сделайте 10 миллионов запросов и измерьте это.
По сравнению с обычным вызовом функции, вы платите за два косвенные ссылки для вызова функции, что аналогично накладным расходам при вызове (не девиртуализированной) виртуальной функции.
Первое косвенное указание связано с удалением типа, которое происходит в boost::function (это документированный в boost::function
документация).Этот на самом деле не может быть оптимизирован, и у вас был бы такой же штраф и с голым указателем на функцию.
Второе косвенное указание исходит из вызова mycallback
функция через указатель на функцию.Очень хорошо оптимизированный компилятор может вычислить это и оптимизировать, но обычный компилятор этого не сделает.Вы можете избавиться от этой косвенности (во всех компиляторах), если вы включите mycallback
в функциональный объект:
Вместо того , чтобы
void mycallback( .1. ) { .2. }
ты делаешь
struct mycallback {
void operator()( .1. ) const { .2. }
};
Имейте в виду, что boost::bind вызывает Копировать функтора.Это может быть очень важно.Для моей операционной системы новости и удаления обходятся очень дорого.Смотрите документацию boost::bind о ref() и cref().Я считаю, что функции-члены также вызывают копии функторов, но документации по этому поводу нет.