Ускорьте ASIO с помощью CRTP или PBCP или набора текста по утке

Я хотел написать оболочку для надстройки ASIO для реализации клиент / сервер TCP. Интерфейс boost ASIO действительно хорош, но причина в том, что оболочка должна быть в состоянии заменить цикл обработки событий чем-то другим. В нашем сценарии использования нам просто нужно вызывать одну и ту же функцию-обработчик для каждого асинхронного чтения, приложению не нужно передавать обработчик для каждого вызова asyncRead. Так что это помогает зарегистрировать обработчик за один раз. Один из способов, который я попробовал, таков:

template <class Connection>
struct TCPClient { // implements the interface with ASIO

Connection *_connection;

void setConnection (Connection *connection)
{
_connection = connection;
}

void asyncRead ()
{
_socket.async_read_some(boost::asio::null_buffers(),
[this] (ErrorType err, unsigned a) {

if (_connection) _connection->handleRead(err);
if (!err) asyncRead();
});
}

};

Я мог бы сделать то же самое с CRTP

class MyConnection : public TCPClient<MyConnection> {
void readHandler (TCPClient::ErrType err)
{
}
};

И в классе TCPClient asyncRead будет

void asyncRead ()
{
_socket.async_read_some(boost::asio::null_buffers(),
[this] (ErrorType err, unsigned a) {
((Connection *)this)->handleRead(err);
if (!err) asyncRead();
});
}

Это на всякий случай полезно, так как время жизни TCPClient и соединения одинаково.

Или PBCP

template <typename Connection>
class TCPClient : public Connection {

void asyncRead ()
{
_socket.async_read_some(boost::asio::null_buffers(),
[this] (ErrorType err, unsigned a) {
Connection::handleRead(err);
if (!err) asyncRead();
});
}
};

Я не думаю, что на самом деле существует отношение IS-A к ч / б TCPCLient и Connection. Я запутался, если какая-то из этих схем хороша. (Также мне интересно, почему в ASIO нет схемы, в которой кешируется обработчик один раз и вызывается каждый раз. По крайней мере, в случае асинхронного чтения, как правило, отсутствует возвращаемый контекст. В нашем случае скорость чтения сообщений является самой большой проблемой и Ускорение ASIO-копирования каждый раз при чтении обработчика чтения + выделение памяти для хранения действительно плохо. Поэтому, основываясь на результатах теста, нам, возможно, придется изменить цикл обработки событий на что-то нестандартное)

1

Решение

Я проделал некоторую работу в этом смысле.
В вашем базовом классе CRTP вы можете попытаться создать параметризованный шаблонный метод, который вызывает производный класс и устанавливает станд :: функция удерживая лямбу, которую нужно передать async_read / write.

Базовый класс:

template <class Connection>
struct TCPClient { // implements the interface with ASIO

std::function<void(const boost::system::error&) handler{};

void registerConnectionHandler(std::function<void(const boost::system::error&)> &&impl)
{
static_cast<MyConnection*>(this)->registerConnectionHandler(std::forward<decltype(impl)>(impl));
}

void asyncRead ()
{
_socket.async_read_some(boost::asio::null_buffers(), handler);
}

};

В производном классе:

class MyConnection : public TCPClient<MyConnection> {
public:
void registerConnectionHandler(std::function<void(const boost::system::error&)> &&impl)
{
handler = std::move(impl);
}
};

Другой способ сделать это — реализовать обработчик в производном классе, не используя registerConnectionHandler с std :: function, что, вероятно, является лучшим способом сделать это:

class MyConnection : public TCPClient<MyConnection> {
public:
void registerConnectionHandler()
{
handler =  [this](const boost::system::error &err)
{
// your stuff here
};
}
};
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]