My tcp server is based on this boost coroutine server example.
There're lots of request per second, the server have two cores but only one is used, it never goes over than 50% cpu in task manager's performance tab, and one core is always free:
How to make boost::coroutine work with multiple cores?
I just came up a solution that add a thread_pool:
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp>
#include "thread_pool.h"
#include <iostream>
using boost::asio::ip::tcp;
class session : public std::enable_shared_from_this<session>
{
public:
explicit session(tcp::socket socket) { }
void go()
{
std::cout << "dead loop" << std::endl;
while(1) {} // causes 100% cpu usage, just for test
}
};
int main()
{
try
{
boost::asio::io_service io_service;
thread_pool pool(1000); // maximum 1000 threads
boost::asio::spawn(io_service,
[&](boost::asio::yield_context yield)
{
tcp::acceptor acceptor(io_service,
tcp::endpoint(tcp::v4(), 80));
for (;;)
{
boost::system::error_code ec;
tcp::socket socket(io_service);
acceptor.async_accept(socket, yield[ec]);
if (!ec) {
pool.enqueue([&] { // add this to pool
std::make_shared<session>(std::move(socket))->go();
});
}
}
});
io_service.run();
}
catch (std::exception& e)
{}
return 0;
}
Now the code seems running with 100% cpu after telnet 127.0.0.1 80 twice.
But what's the common way of using coroutine with multi cores?
One thread only runs on one core, so you have to create multiple threads with separate coroutines. asio already contains some thread management support, so you mostly have to start some threads:
int main() {
std::vector<std::thread> pool;
try {
boost::asio::io_service io_service;
{
for(auto threadCount = std::thread::hardware_concurrency();
threadCount;--threadCount)
pool.emplace_back([](auto io_s) {return io_s->run(); }, &io_service);
}
// Normal code
} catch(std::exception &e) {}
for(auto &thread : pool)
thread.join();
return 0;
}
The important thing is to run io_service.run()
on every thread. Then, after .async_accept
, you can call
io_service.post(&session::go, std::make_shared<session>(std::move(socket)))
to run the session somewhere in the pool.