Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> обертка над asio сокетом 
V
    Опции темы
boostcoder
Дата 10.4.2011, 20:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



всем доброго вечера.

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

сейчас вижу интерфейс таким:
Код

struct socket {
   template<typename T, typename F>
   void async_write(T& buf, F handler) {
      ... = buf.begin();
      ... = buf.end();
   }

   template<typename F>
   void async_write(char* buf, size_t len, F handler) {
   }
};


чтоб использовать так:
Код

socket sock;

void handler(const boost::system::error_code& e) {}

std::string str;
boost::array<char, 32> arr;
std::vector<char> vec;

sock.async_write(str, &handler);
sock.async_write(arr, &handler);
sock.async_write(vec, &handler);


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

спасибо.

PM WWW   Вверх
borisbn
Дата 10.4.2011, 23:45 (ссылка) |  (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(boostcoder @  10.4.2011,  20:11 Найти цитируемый пост)
первый вопрос - есть ли смысл вообще в обертке?

думаю есть, т.к. довольно часто приходится делать одно и то же, наступать на те же грабли, копипастить... брррр

Цитата(boostcoder @  10.4.2011,  20:11 Найти цитируемый пост)
второй вопрос - в случае записи указателя на char, есть ли смысл копировать данные в какой-то внутренний буфер обертки? или просто запоминать указатель, по при вызове хэндлера - освобождать память на которую он указывает?

IMHO однозначно копировать. чтобы не получилось такой ситуации
Код

sock.async_write( obj.getTempString().c_str(), ...


Цитата(boostcoder @  10.4.2011,  20:11 Найти цитируемый пост)
третий вопрос - что вообще нужно такой обертке, и что не нужно?

IMHO лучше интерфеса, чем этот не придумаешь

Это сообщение отредактировал(а) borisbn - 10.4.2011, 23:53


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
bsa
Дата 10.4.2011, 23:51 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Цитата(boostcoder @  10.4.2011,  20:11 Найти цитируемый пост)
второй вопрос - в случае записи указателя на char, есть ли смысл копировать данные в какой-то внутренний буфер обертки?
да, конечно.
Цитата(boostcoder @  10.4.2011,  20:11 Найти цитируемый пост)
или просто запоминать указатель, по при вызове хэндлера - освобождать память на которую он указывает?
ни в коем случае. Память освобождаться должна там, где была выделена.
PM   Вверх
boostcoder
Дата 11.4.2011, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(borisbn @  10.4.2011,  23:45 Найти цитируемый пост)
однозначно копировать

Цитата(bsa @  10.4.2011,  23:51 Найти цитируемый пост)
да, конечно.

допустим...
тогда встает вопрос о размере внутреннего буфера обертки.
1. должен указываться в конструкторе?
2. или увеличивается столько, сколько свободной памяти на машине?
3. расходы на выделение памяти/копирование не пугают?

у меня есть такое предложение: обязать пользователя передавать в сокет смарт_поинтер инициализированный/заполненный юзером.
в этом есть есть два плюса:
1. не нужно ничего копировать. т.к. внутренний буфер становится очередью из смарт_поинтеров
2. не нужно руками освобождать память.

PM WWW   Вверх
mes
Дата 11.4.2011, 12:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  10.4.2011,  19:11 Найти цитируемый пост)
хочу избавиться от ручного написания байнда и хранения записываемого буфера до окончания асинхронной операции.

нельзя ли пример строчки которая Вас не устраивает, с указанием неугодных  моментов ?.. 


--------------------
PM MAIL WWW   Вверх
borisbn
Дата 11.4.2011, 12:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(boostcoder @  11.4.2011,  11:14 Найти цитируемый пост)
1. должен указываться в конструкторе?

IMHO некрасиво

Цитата(boostcoder @  11.4.2011,  11:14 Найти цитируемый пост)
2. или увеличивается столько, сколько свободной памяти на машине?

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

Цитата(boostcoder @  11.4.2011,  11:14 Найти цитируемый пост)
3. расходы на выделение памяти/копирование не пугают?

Думаю, что сама отправка (скорость передачи по каналу) будет на порядки дольше, чем обращение к менеджеру памяти и копирование из одной области памяти в другую. Даже если передача данных будет происходить по 127.0.0.1


Цитата(boostcoder @  11.4.2011,  11:14 Найти цитируемый пост)
обязать пользователя передавать в сокет смарт_поинтер инициализированный/заполненный юзером.

В этом случае юзерская ф-ция отправки, например, строки будет выглядеть некрасиво
Код

void user_send( const std::string & str ) {
    size_t sz = str.length();
    shared_ptr< char > p( new char[ sz + 1 ] );
    strcpy( p, str.c_str() );
    sock.async_write( p );
}

вместо
Код

void user_send( const std::string & str ) {
    sock.async_write( str.c_str(), str.length() );
}




--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
boostcoder
Дата 11.4.2011, 16:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(borisbn @  11.4.2011,  12:44 Найти цитируемый пост)
Думаю, что сама отправка (скорость передачи по каналу) будет на порядки дольше, чем обращение к менеджеру памяти и копирование из одной области памяти в другую.

тут Вы ошибаетесь.
в этой теме, возьмите последние исходники и посмотрите. там очень простой код. выделение 13 байт, sprintf(), передача в async_write(), в хэндлере delete[]. ничего сложного ведь ;) но на 100мбитной сети, происходит 220000-250000 таких последовательностей, что полносьтю загружает одно ядро. вроде бы казалось, ничего сложного в этих операциях нет. но профайлер говорит что 48 процентов времени уходит только на new!

в общем, выделение памяти и инициализацию смарт_поинтера оставил на юзера. помоему, очень даже юзабельно получилось smile 
пожелания/рекомендации/критика приветствуются.

класс сокета:
Код


#ifndef _simple_socket_hpp_included_
#define _simple_socket_hpp_included_

#include <queue>
#include <stdexcept>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/function.hpp>
#include <boost/shared_array.hpp>
#include <boost/system/error_code.hpp>

/***************************************************************************/

struct simple_socket: private boost::noncopyable {
   typedef void(*read_handler_type)(const boost::system::error_code&, boost::shared_array<char>, size_t);
   typedef void(*write_handler_type)(const boost::system::error_code&, boost::shared_array<char>, size_t);

   simple_socket(boost::asio::io_service& ios)
      :sock(ios),
      write_in_process(false),
      read_in_process(false)
   {}

   ~simple_socket() {
      clear_read_queue();
      clear_write_queue();
      disconnect();
   }

   boost::asio::ip::tcp::socket& socket() { return sock; }

   void connect(const std::string& ip, boost::uint16_t port) {
      sock.connect(
         boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(ip), port)
      );
   }
   void disconnect() {
      if ( sock.is_open() ) {
         sock.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
         sock.close();
      }
   }

   size_t read_queue_size() const { return read_queue.size(); }
   size_t write_queue_size() const { return write_queue.size(); }

   void clear_read_queue() {
      read_queue.clear();
      if ( sock.is_open() ) sock.cancel();
   }
   void clear_write_queue() {
      write_queue.clear();
      if ( sock.is_open() ) sock.cancel();
   }

   template<typename F>
   void async_write(boost::shared_array<char> arr, size_t size, F f) {
      if ( !sock.is_open() ) throw std::runtime_error("socket is not connected");
      if ( !arr.get() || !size ) return;
      write_queue.push({f, arr, size});
      if ( !write_in_process ) {
         write_in_process = true;
         write_exec();
      }
   }
   void async_write(boost::shared_array<char> arr, size_t size, write_handler_type f) {
      async_write(arr, size, boost::bind(f, _1, _2, _3));
   }
   template<typename Obj>
   void async_write(boost::shared_array<char> arr,
                    size_t size,
                    Obj* obj,
                    void(Obj::*handler)(const boost::system::error_code&, boost::shared_array<char>, size_t))
   {
      async_write(arr, size, boost::bind(handler, obj, _1, _2, _3));
   }
   
   template<typename F>
   void async_read(size_t size, F f) {
      if ( !sock.is_open() ) throw std::runtime_error("socket is not connected");
      if ( !size ) return;
      read_queue.push({f, boost::shared_array<char>(), size});
      if ( !read_in_process ) {
         read_in_process = true;
         read_exec();
      }
   }
   void async_read(size_t size, read_handler_type f) {
      async_read(size, boost::bind(f, _1, _2, _3));
   }
   template<typename Obj>
   void async_read(size_t size,
                   Obj* obj,
                   void(Obj::*handler)(const boost::system::error_code&, boost::shared_array<char>, size_t))
   {
      async_read(size, boost::bind(handler, obj, _1, _2, _3));
   }

private:
   typedef boost::function<void(const boost::system::error_code&, boost::shared_array<char>, size_t)> handler_type;
   
   struct pair {
      handler_type handler;
      boost::shared_array<char> buf;
      size_t size;
   };

   void write_exec() {
      pair p = write_queue.pop();

      boost::asio::async_write(
         sock,
         boost::asio::buffer(p.buf.get(), p.size),
         boost::bind(
            &simple_socket::write_exec_handler,
            this,
            p,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred
         )
      );
   }

   void write_exec_handler(pair p, const boost::system::error_code& e, size_t wr) {
      p.handler(e, p.buf, wr);
      if ( !write_queue.empty() ) {
         write_exec();
      } else {
         write_in_process = false;
      }
   }

   void read_exec() {
      pair p = read_queue.pop();
      p.buf.reset(new char[p.size]);

      boost::asio::async_read(
         sock,
         boost::asio::buffer(p.buf.get(), p.size),
         boost::bind(
            &simple_socket::read_exec_handler,
            this,
            p,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred
         )
      );
   }

   void read_exec_handler(pair p, const boost::system::error_code& e, size_t rd) {
      p.handler(e, p.buf, rd);
      if ( !read_queue.empty() ) {
         read_exec();
      } else {
         read_in_process = false;
      }
   }

private:
   template<typename T>
   struct queue {
      void push(T p) {
         boost::mutex::scoped_lock locker(mutex);
         queue.push(p);
      }
      
      T pop() {
         boost::mutex::scoped_lock locker(mutex);
         if ( queue.empty() ) {
            throw std::runtime_error("queue is empty");
         }
         T p = queue.front();
         queue.pop();
         return p;
      }

      void clear() {
         boost::mutex::scoped_lock locker(mutex);
         while ( !queue.empty() ) {
            queue.pop();
         }
      }
      
      bool empty() const {
         boost::mutex::scoped_lock locker(mutex);
         return queue.empty();
      }

      size_t size() const {
         boost::mutex::scoped_lock locker(mutex);
         return queue.size();
      }
      
   private:
      mutable boost::mutex mutex;
      std::queue<T> queue;
   };

   boost::asio::ip::tcp::socket sock;
   
   queue<pair> write_queue;
   bool write_in_process;
   
   queue<pair> read_queue;
   bool read_in_process;
};

/***************************************************************************/

#endif // _simple_socket_hpp_included_



пример 1:
Код


#include "simple_socket.hpp"
#include <iostream>

/***************************************************************************/

void write_handler(const boost::system::error_code& e, boost::shared_array<char> arr, size_t wr) {
   fprintf(stdout, "write_handler(): %s, %d, e = %s\n", arr.get(), wr, e.message().c_str());
   fflush(stdout);
}

void read_handler(const boost::system::error_code& e, boost::shared_array<char> arr, size_t rd) {
   fprintf(stdout, "read_handler(): %s, %d, e = %s\n", arr.get(), rd, e.message().c_str());
   fflush(stdout);
}

/***************************************************************************/

int main() {
   enum {
      array_size = 32,
      count = 1024
   };

   boost::asio::io_service ios;
   simple_socket socket(ios);

   try {
      socket.connect("127.0.0.1", 44550);

      for(int idx = 0; idx < count; ++idx) {
         boost::shared_array<char> arr(new char[array_size]);
         sprintf(arr.get(), "item: %d", idx);

         socket.async_write(arr, array_size, &write_handler);
      }
      
      for(int idx = 0; idx < count; ++idx) {
         socket.async_read(array_size, &read_handler);
      }

      ios.run();
      socket.disconnect();
   }
   catch(const std::exception& e) {
      std::cout << "[exception] " << e.what() << std::endl;
   }
}

/***************************************************************************/



пример 2:
Код


#include "simple_socket.hpp"
#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

/***************************************************************************/

struct client_impl {
   client_impl(boost::asio::io_service& ios, const std::string& ip, boost::uint16_t port)
      :socket(ios),
      str("string data")
   {
      socket.connect(ip, port);
   }

   void write() {
      const size_t len = strlen(str);
      boost::shared_array<char> arr(new char[len]);
      strcpy(arr.get(), str);
      
      socket.async_write(arr, len, this, &client_impl::write_handler);
   }
   void read() {
      socket.async_read(strlen(str), this, &client_impl::read_handler);
   }

   void write_handler(const boost::system::error_code& e, boost::shared_array<char> arr, size_t wr) {
      fprintf(stdout, "write_handler(): %s, %d, e = %s\n", arr.get(), wr, e.message().c_str());
      fflush(stdout);
   }

   void read_handler(const boost::system::error_code& e, boost::shared_array<char> arr, size_t rd) {
      fprintf(stdout, "read_handler(): %s, %d, e = %s\n", arr.get(), rd, e.message().c_str());
      fflush(stdout);
   }

private:
   simple_socket socket;
   const char* str;
};

/***************************************************************************/

int main() {
   boost::asio::io_service ios;
   client_impl client(ios, "127.0.0.1", 44550);

   try {
      client.write();
      client.read();
      ios.run();
   }
   catch(const std::exception& e) {
      std::cout << "[exception] " << e.what() << std::endl;
   }
}

/***************************************************************************/



пример 3:
Код


#include "simple_socket.hpp"
#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread.hpp>

/***************************************************************************/

struct client_impl {
   void write_handler(const boost::system::error_code& e, boost::shared_array<char> arr, size_t wr) {
      fprintf(stdout, "write_handler(): %s, %d, e = %s\n", arr.get(), wr, e.message().c_str());
      fflush(stdout);
   }

   void read_handler(const boost::system::error_code& e, boost::shared_array<char> arr, size_t rd) {
      fprintf(stdout, "read_handler(): %s, %d, e = %s\n", arr.get(), rd, e.message().c_str());
      fflush(stdout);
   }
};

/***************************************************************************/

int main() {
   boost::asio::io_service ios;
   simple_socket socket(ios);

   client_impl client;

   try {
      socket.connect("127.0.0.1", 44550);

      const size_t arr_size = 32;
      boost::shared_array<char> arr(new char[arr_size]);
      sprintf(arr.get(), "data string");
      
      socket.async_write(arr, arr_size, &client, &client_impl::write_handler);

      socket.async_read(arr_size, &client, &client_impl::read_handler);
      
      ios.run();
   }
   catch(const std::exception& e) {
      std::cout << "[exception] " << e.what() << std::endl;
   }
}

/***************************************************************************/



всем спасибо smile

Добавлено через 6 минут и 9 секунд
Цитата(mes @  11.4.2011,  12:00 Найти цитируемый пост)
нельзя ли пример строчки которая Вас не устраивает, с указанием неугодных  моментов ?

не нравится постоянно писать байнд.
в добавок, если сигнатура не соответствует, или не соответствует кол-во плейсхолдеров, или их вовсе нет - то глядеть в 120 строк вывода об ошибке сомнительное удовольствие.

Это сообщение отредактировал(а) boostcoder - 11.4.2011, 16:35

Присоединённый файл ( Кол-во скачиваний: 2 )
Присоединённый файл  simplesocket.zip 3,33 Kb
PM WWW   Вверх
boostcoder
Дата 11.4.2011, 16:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



эм... такой вопрос: а есть ли смысл добавлять методы для синхронных операций?
IMHO - лишнее.
PM WWW   Вверх
borisbn
Дата 11.4.2011, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(boostcoder @  11.4.2011,  16:32 Найти цитируемый пост)
профайлер говорит что 48 процентов времени уходит только на new!

профайлер не знает, сколько времени уходит непосредственно на отправку/приём, т.к. они асинхронные
В Вашем примере ровно столько же new делается на стороне клиента юзера

Цитата(boostcoder @  11.4.2011,  16:32 Найти цитируемый пост)

for(int idx = 0; idx < count; ++idx) {
         boost::shared_array<char> arr(new char[array_size]);

думаю, что эти new как-то можно соптимизировать. и лучше это сделать в одном месте - в обёртке, а не каждый раз у юзера. А не замахнуться ли нам на Вильяма нашего Собственного Менеджера Памяти smile

Цитата(boostcoder @  11.4.2011,  16:53 Найти цитируемый пост)
а есть ли смысл добавлять методы для синхронных операций?

думаю, Вы правы. Лишнее. А вот добавить [необязательные] handler'ы connected и disconnected можно smile


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
boostcoder
Дата 11.4.2011, 17:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(borisbn @  11.4.2011,  17:15 Найти цитируемый пост)
 Вашем примере ровно столько же new делается на стороне клиента юзера

это да. но я хотел сказать то, что ко всем new не нужно еще и добавлять расходы на копирование.

Цитата(borisbn @  11.4.2011,  17:15 Найти цитируемый пост)
думаю, что эти new как-то можно соптимизировать. и лучше это сделать в одном месте - в обёртке, а не каждый раз у юзера.

как, например?
пул памяти?

Цитата(borisbn @  11.4.2011,  17:15 Найти цитируемый пост)
connected и disconnected

ага. а потом кто-то скажет еще добавить аксессоры для ip:port, и что-то еще smile 
у обертки есть метод socket() который возвращает ссылку на внутренний сокет. а у него есть все необходимые методы.

эта обертка - всего лишь сокет.
над ней можно написать другую обертку, к примеру обертку сериализатора/десериализатора для абстрагирования от типа. т.к. сейчас обертка работает только с массивом чаров.


Это сообщение отредактировал(а) boostcoder - 11.4.2011, 18:24
PM WWW   Вверх
boostcoder
Дата 11.4.2011, 17:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(borisbn @  11.4.2011,  17:15 Найти цитируемый пост)
А не замахнуться ли нам на Вильяма нашего Собственного Менеджера Памяти

предлагаешь написать менеджер памяти?
и кто такой "Вильяма" ?

PM WWW   Вверх
mes
Дата 11.4.2011, 18:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  11.4.2011,  16:39 Найти цитируемый пост)
и кто такой "Вильяма" 

http://www.bibliotekar.ru/encSlov/a/25.htm


--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 11.4.2011, 18:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



mes, спасибо.
я никогда не понимал классику. потому не смотрел. потому не знаю таких высказываний.

хотя... Кин-дза-дза мне нравится. помоему это единственное из классики что я могу посмотреть без принуждения..


Это сообщение отредактировал(а) boostcoder - 11.4.2011, 18:44
PM WWW   Вверх
boostcoder
Дата 11.4.2011, 19:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



mes, кстати. как Вам такой сокет? ;)
PM WWW   Вверх
phprus
Дата 11.4.2011, 20:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 129
Регистрация: 22.8.2006

Репутация: 1
Всего: 3



Цитата(borisbn @  11.4.2011,  15:44 Найти цитируемый пост)
Думаю, что сама отправка (скорость передачи по каналу) будет на порядки дольше, чем обращение к менеджеру памяти и копирование из одной области памяти в другую. Даже если передача данных будет происходить по 127.0.0.1

Аллокации, влияют не так сильно, а вот копирование памяти, ее предварительное зануление(если используется std::vector) начинает тормозить уже на скорости обмена с сетью порядка 200Мбит/с (выведено из опыта излишней буферизации в своем приложении), то есть скорость работы приложения ограничивается скоростью копирования памяти.

Цитата(borisbn @  11.4.2011,  15:44 Найти цитируемый пост)
    shared_ptr< char > p( new char[ sz + 1 ] );

shared_ptr не может принимать массивы, и не во всех случаях безопасен при многопоточности. В первом случае есть shared_array, а второй так просто не решается :(
PM MAIL WWW ICQ   Вверх
mes
Дата 11.4.2011, 21:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(boostcoder @  11.4.2011,  18:02 Найти цитируемый пост)
mes, кстати. как Вам такой сокет? ;) 

внимательно не рассматривал, но интуитивно не очень.. 



--------------------
PM MAIL WWW   Вверх
boostcoder
Дата 11.4.2011, 21:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(phprus @  11.4.2011,  20:37 Найти цитируемый пост)
Аллокации, влияют не так сильно

запустите код из этой темы под профайлером. и сами посмотрите на результат. не думаю что профайлер врет.

Цитата(phprus @  11.4.2011,  20:37 Найти цитируемый пост)
второй так просто не решается

это интересный момент..

PM WWW   Вверх
borisbn
Дата 12.4.2011, 09:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(phprus @  11.4.2011,  20:37 Найти цитируемый пост)
shared_ptr не может принимать массивы

принимать может ( http://liveworkspace.org/code/93c25ddc57b2...c6880d858a56139 )
удаляет неправильно (без [])


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
mabrarov
Дата 12.4.2011, 23:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 12.1.2011
Где: Казань

Репутация: 8
Всего: 9



Цитата

запустите код из этой темы под профайлером. и сами посмотрите на результат. не думаю что профайлер врет.


Вы просто забыли, что такое шаблон Proactor и как важен для него механизм, предоставляемый Boost.Asio: custom memory allocation (http://www.boost.org/doc/libs/1_46_1/doc/html/boost_asio/overview/core/allocation.html)

С этим механизмом (с его применением) Вы сильно удивитесь резвости asio, так как в этом случае все аллокаци во всех используемых очередях (io_service, io_service::strand, deadline_timer) могут свестись к банальному:
Код

void* allocate(std::size_t size)
{
  if (!in_use_ && size <= storage_.size)
  {
    in_use_ = true;
    return storage_.address();
  }      
  return ::operator new(size);      
}

void deallocate(void* pointer)
{
  if (pointer == storage_.address())
  {        
    in_use_ = false;
    return;
  }      
  ::operator delete(pointer);      
}

PM MAIL WWW Skype   Вверх
boostcoder
Дата 13.4.2011, 01:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



mabrarov, Марат, здравствуйте ;)
по приведенной вами ссылке, читал, и не раз.
не могли бы Вы популярно объяснить, и, желательно с примером. буду сильно благодарен.
спасибо.


Это сообщение отредактировал(а) boostcoder - 13.4.2011, 02:13
PM WWW   Вверх
mabrarov
Дата 13.4.2011, 02:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 12.1.2011
Где: Казань

Репутация: 8
Всего: 9



Цитата(boostcoder @ 13.4.2011,  01:39)
mabrarov, Марат, здравствуйте ;)
по приведенной вами ссылке читал, и не раз. не могли бы Вы популярно объяснить, и, желательно с примером. буду сильно благодарен.
спасибо.

А я думал, что уже достал Вас   smile 

Объяснить проще, чем в примерах Boost.Asio, я не смогу. К сожалению, проще уже некуда.
Могу только пояснить следующее: как любая система построенная по шаблону Proactor (да и вообще - как все многопоточные системы, базирующиеся на очередях - т.е. почти все более-менее "продвинутые" многопоточные системы, например, Intel TBB), asio активно использует очереди (в случае asio - это очереди из функциональных объектов). 

В связи с этим остро встает вопрос выделения памяти в таких очередях (особенно остро в свете многопоточности и кешей процессора). Intel TBB решает это своим "прокаченным-специализированным" аллокатором (и обещаниями повторно использовать выделяемые блоки). 

asio использует очень легкое и гибкое решение (и это не единственный случай!): позволяет использовать allocator per async operation (начиная с dev release 1.53 - во всех асинхронных операциях). И вот какая штука: в любом вменяемом (т.е. не "hello world") приложении количество одновременных однотипных асинхронных операций над одним и тем же объектом (например, socket или deadline_timer) всегда ограничено сверху. И зачастую это ограничение равно единице (Вы уже на него нарвались недавно).

Исходя из всего вышесказанного, зачастую, Вы можете просто заранее выделить непрерывный блок памяти, который будет удерживаться Вашим handler-ом (например, при помощи shared_ptr). Затем, каждый раз когда asio будет нужна память для чего-то временного (обычно, это память для расположения в очереди - IOCP или boost::asio::io_service::strand или даже deadline_timer), что связанно с асинхронной операцией, для которой Ваш handler является completion handler-ом - asio просто попросит об этом через Ваш же handler. При этом те гарантии что дает asio относительно custom memory allocation, гарантируют, что (при достаточном размере Вашего пред-аллоцированного блока памяти) Вы всегда сможете выделить  эту память из того самого, ранее выделенного, блока памяти.

Кроме того, гарантии asio позволяют удерживать этот "пред-аллоцированный блок памяти" самим же handler-ом (с небольшим ограничением на handler - см. доки по Boost.Asio 1.53, почти всегда это ограничение выполняется и уж точно всегда его можно легко обойти). Главное, хранить в handler-е не сам блок, а указатель на него (лучше -smart) - чтобы в блок помещался сам handler + что-то временное.

В моем проекте (http://sourceforge.net/projects/asio-samples) echo_server (и qt_echo_server, и, вообще, все "asio samples") вообще не выделяет память в куче при своей непосредственной работе (кроме приема новых входящих TCP-соединений, да и тут есть reuse). Custom memory allocation сводит все выделения памяти к тому коду, что я указал - т.е. никаких блокировок и даже никаких атомарных (interlocked) операций. Плюс, в теории (не могу до сих пор проверить) - это должно очень положительно сказаться на использовании CPU-кеша (+ учтите очень правильную реализацию strand-ов в asio).

Это сообщение отредактировал(а) mabrarov - 13.4.2011, 02:16
PM MAIL WWW Skype   Вверх
boostcoder
Дата 29.5.2011, 06:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mabrarov @  13.4.2011,  02:14 Найти цитируемый пост)
allocator per async operation (начиная с dev release 1.53 - во всех асинхронных операциях)

возможно я не туда смотрю..
вот дока asio-1.4.9 входящая в состав boost-1.46.1: http://www.boost.org/doc/libs/1_46_1/doc/h...allocation.html
а вот дока asio-1.5.3 с офф. сайта: http://think-async.com/Asio/asio-1.5.3/doc...allocation.html

не вижу разницы.
или я не туда смотрю?
PM WWW   Вверх
mabrarov
Дата 30.5.2011, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 12.1.2011
Где: Казань

Репутация: 8
Всего: 9



Цитата(boostcoder @ 29.5.2011,  06:52)
Цитата(mabrarov @  13.4.2011,  02:14 Найти цитируемый пост)
allocator per async operation (начиная с dev release 1.53 - во всех асинхронных операциях)

возможно я не туда смотрю..
вот дока asio-1.4.9 входящая в состав boost-1.46.1: http://www.boost.org/doc/libs/1_46_1/doc/h...allocation.html
а вот дока asio-1.5.3 с офф. сайта: http://think-async.com/Asio/asio-1.5.3/doc...allocation.html

не вижу разницы.
или я не туда смотрю?

Вот и я не увидел. Но в release notes к asio-1.5.3 все четко сказано. А уж в коде я сразу "порылся" 8) - ждал этого с самого рождения asio.
Не увидел и написал Christopher M. Kohlhoff об этом. Он вежливо поблагодарил за замеченную неточность и... ничего не исправил.

PM MAIL WWW Skype   Вверх
boostcoder
Дата 30.5.2011, 10:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mabrarov @  30.5.2011,  10:07 Найти цитируемый пост)
и... ничего не исправил

 smile 
"великий OpenSource" (с)

остается ждать.
PM WWW   Вверх
mabrarov
Дата 30.5.2011, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 12.1.2011
Где: Казань

Репутация: 8
Всего: 9



К слову, документация у Christopher M. Kohlhoff ну просто очень и очень хорошая (только надо не забывать, что примеры в ней тоже являются обязательным чтивом). 
Думаю:
1) когда asio-1.5.3 войдет в Boost C++ Libraries, все будет исправлено;
2) сразу после выхода asio-1.5.3 Chris уже должен был готовиться к BoostCon 2011;
3) судя по тому, что я читал в рассылке asio-users, он действительно занят коммерческими проектами, остается только поражаться тому, как он находит время и силы и вносит столь серьезные (и долгожданные) изменения, как move semantic support и custom memory allocation support for SSL async operations. 

PM MAIL WWW Skype   Вверх
boostcoder
Дата 30.5.2011, 10:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mabrarov @  30.5.2011,  10:47 Найти цитируемый пост)
документация у Christopher M. Kohlhoff ну просто очень и очень хорошая

не могу согласиться. увы :(

полагаю, сейчас отпишется не один программист, разделяющий мою точку зрения ;)
ибо я такое слышу каждый день(ну почти) от знакомых и коллег.
PM WWW   Вверх
mabrarov
Дата 30.5.2011, 11:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 12.1.2011
Где: Казань

Репутация: 8
Всего: 9



Цитата(boostcoder @ 30.5.2011,  10:54)
полагаю, сейчас отпишется не один программист, разделяющий мою точку зрения ;)
ибо я такое слышу каждый день(ну почти) от знакомых и коллег.

Радует, значит про Asio на просторах СНГ слышали и даже используют.
А если чего-то в документации Asio не хватает, то... для этого и существуют asio samples. Дай бог времени и желания - напишу пару статей на русском про наиболее частые ошибки разработчиков, пытающихся использовать Asio вопреки определенным в документации ограничениям/гарантиям.
Ну и да, это Open Source (и даже не GPL) - поэтому прежде чем переводить production code на Boost.Asio я внимательно изучал его исходники. Это многое открывает, особенно в плане понимания производительности Asio в сравнении с "raw WinSock".
Сравните документацию по Boost.Asio с документацией по ACE или даже с книгами по ACE.
PM MAIL WWW Skype   Вверх
boostcoder
Дата 30.5.2011, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(mabrarov @  30.5.2011,  11:25 Найти цитируемый пост)
для этого и существуют asio samples

вставьте-ка лучше ссылку в подпись. найти будет легче. и, возможно, гугл проиндексирует.

Цитата(mabrarov @  30.5.2011,  11:25 Найти цитируемый пост)
Сравните документацию по Boost.Asio с документацией по ACE или даже с книгами по ACE

когда я только начал постигать _network_programming_in_c++_, я пересмотрел несколько библиотек, и ACE одна из них. но от нее я отказался, в виду монструозности. поэтому не юзал. и о качестве документации вряд-ли смогу сказать уверенно.

PM WWW   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.2560 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.