
Hi,
I'm trying to compare the performance of boost::asio asynchronous vs synchronous IO operations for a single client.
Below, I've sample synchronous and asynchronous server applications, which send 25 byte message to the client in a loop continuously. On the client side, I'm checking at what rate it is able to receive the messages. The sample setup is pretty simple. In synchronous server case, it spawns a new thread per client connection and the thread keeps sending the 25-byte message in a loop. In asynchronous server case as well it spawns a new thread per client connection and the thread keeps sending the 25-byte message in a loop, using asynchronous write (main thread is the one which calls ioservice.run()). For the performance testing I'm using only one client.
*Synchronous server code*
#include <iostream> #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/asio.hpp> #include <boost/thread.hpp>
using boost::asio::ip::tcp;
class tcp_connection : public boost::enable_shared_from_this<tcp_connection> { public: typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service) { return pointer(new tcp_connection(io_service)); }
tcp::socket& socket() { return socket_; }
void start() { for (;;) { try { ssize_t len = boost::asio::write(socket_, boost::asio::buffer(message_)); if (len != message_.length()) { std::cerr<<"Unable to write all the bytes"<<std::endl; break; } if (len == -1) { std::cerr<<"Remote end closed the connection"<<std::endl; break; } } catch (std::exception& e) { std::cerr<<"Error while sending data"<<std::endl; break; } } }
private: tcp_connection(boost::asio::io_service& io_service) : socket_(io_service), message_(25, 'A') { }
tcp::socket socket_; std::string message_; };
class tcp_server { public: tcp_server(boost::asio::io_service& io_service) : acceptor_(io_service, tcp::endpoint(tcp::v4(), 1234)) { start_accept(); }
private: void start_accept() { for (;;) { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service()); acceptor_.accept(new_connection->socket()); boost::thread(boost::bind(&tcp_connection::start, new_connection)); } } tcp::acceptor acceptor_; };
int main() { try { boost::asio::io_service io_service; tcp_server server(io_service); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return 0; }
*ASynchronous server code:* #include <iostream> #include <string> #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/asio.hpp>
#include <boost/thread.hpp>
using boost::asio::ip::tcp;
class tcp_connection : public boost::enable_shared_from_this<tcp_connection> { public: typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service) { return pointer(new tcp_connection(io_service)); }
tcp::socket& socket() { return socket_; }
void start() { while (socket_.is_open()) { boost::asio::async_write(socket_, boost::asio::buffer(message_), boost::bind(&tcp_connection::handle_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } }
private: tcp_connection(boost::asio::io_service& io_service) : socket_(io_service), message_(25, 'A') { }
void handle_write(const boost::system::error_code& error, size_t bytes_transferred) { if (error) { if (socket_.is_open()) { std::cout<<"Error while sending data asynchronously"<<std::endl; socket_.close(); } } }
tcp::socket socket_; std::string message_; };
class tcp_server { public: tcp_server(boost::asio::io_service& io_service) : acceptor_(io_service, tcp::endpoint(tcp::v4(), 1234)) { start_accept(); }
private: void start_accept() { tcp_connection::pointer new_connection = tcp_connection::create(acceptor_.get_io_service()); acceptor_.async_accept(new_connection->socket(), boost::bind(&tcp_server::handle_accept, this, new_connection, boost::asio::placeholders::error)); }
void handle_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error) { if (!error) { boost::thread(boost::bind(&tcp_connection::start, new_connection)); }
start_accept(); }
tcp::acceptor acceptor_; };
int main() { try { boost::asio::io_service io_service; tcp_server server(io_service); io_service.run(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; }
return 0; }
*Client code* #include <iostream>
#include <boost/asio.hpp> #include <boost/array.hpp>
int main(int argc, char* argv[]) { if (argc != 3) { std::cerr<<"Usage: client <server-host> <server-port>"<<std::endl; return 1; }
boost::asio::io_service io_service; boost::asio::ip::tcp::resolver resolver(io_service); boost::asio::ip::tcp::resolver::query query(argv[1], argv[2]); boost::asio::ip::tcp::resolver::iterator it = resolver.resolve(query); boost::asio::ip::tcp::resolver::iterator end; boost::asio::ip::tcp::socket socket(io_service); boost::asio::connect(socket, it);
// Statscollector to periodically print received messages stats // sample::myboost::StatsCollector stats_collector(5); // sample::myboost::StatsCollectorScheduler statsScheduler(stats_collector); // statsScheduler.start();
for (;;) { boost::array<char, 25> buf; boost::system::error_code error; size_t len = socket.read_some(boost::asio::buffer(buf), error); // size_t len = boost::asio::read(socket, boost::asio::buffer(buf)); if (len != buf.size()) { std::cerr<<"Length is not "<< buf.size() << " but "<<len<<std::endl; } // stats_collector.incr_msgs_received(); } }
<b>Question:* When the client is running against synchronous server it is able to receive around 700K msgs/sec but when it is running against asynchronous server the performance is dropped to around 100K-120K msgs/sec. I know that one should use asynchronous IO for scalability when we have more number of clients and in the above case as I'm using only a single client, the obvious advantage of asynchronous IO is not evident. But the question is, is asynchronous IO expected to effect the performance so badly for a single client case or am I missing some obvious best practices to follow with asynchronous IO? Is the significant drop in the performance is because of the thread switch between ioservice thread (which is main thread in the above case) and connection thread?
*Setup:* I'm using BOOST 1.47 on Linux machine.
-- View this message in context: http://boost.2283326.n4.nabble.com/boost-asio-synchronous-vs-asynchronous-op... Sent from the Boost - Users mailing list archive at Nabble.com. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users http://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/reference/io_servic... Try using concurrency_hint = number of threads you'll create. At least with I/O Completion ports (Windows NT), only concurrency_hint
On 3/21/2014 12:54, Donald Alan wrote: threads can perform an asynchronous operation simultaneously. All other threads have to wait. The default constructor probably uses concurrency_hint = #processors but tbh I'm not sure. disclaimer: I'm also not sure if I/O Completion ports actually supports more threads than #processors. MSDN doesn't suggest that there's any limit. Also, the main point of asynchronous I/O is that you don't need a thread-per-file/connection to achieve necessary performance. A typical asynchronous I/O server will have either 1 or #processors dedicated I/O threads and use a fixed number of worker threads for non-IO tasks, not a thread-per-connection. I would suggest that this renders your benchmark questionable even after you make my suggested change.