Вопрос

В настоящее время я работаю над сетевым программным обеспечением.У него есть один основной класс, 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().Я считаю, что функции-члены также вызывают копии функторов, но документации по этому поводу нет.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top