提升async_read与阻塞同步线程 - 性能差异?

时间:2017-10-29 06:12:45

标签: c++ boost boost-asio

我很好奇如果在使用Boost ASIO中的异步读取功能与使用同步读取的单独线程相比具有任何性能优势。用例必须始终监听来自远程主机的数据。

在异步的情况下,我相信ioservice.run()会阻塞线程,直到有数据要读取。在同步的情况下,boost :: asio:read调用将阻塞,直到有数据要读取。使用异步读取有什么好处吗?看起来如果应用程序在等待数据时需要在后台进行任何操作,则在使用async_read时也需要单独的线程,因为ioservice_run()将阻塞。

代码将类似于以下内容(可能无法编译,只是试图了解这个想法):

使用异步读取:

#include <iostream>
#include <boost/asio.hpp>

void read_handler(const boost::system::error_code &ec)
{
    //Read incoming message

    //Chain the callbacks
    socket.async_read(read_handler);
}

int main()
{
    std::string host = "192.168.1.3";
    std::string port = "8888";
    std::cout << "Attemping connection to host " << host << " on port " << port << std::endl;
    boost::asio::connect(tcpSocket, resolver.resolve({host, port}));
    std::cout << "Connected" << std::endl;

    socket.async_read(read_handler);

    //Will block until there is data to read?
    ioservice.run();
    return 0;
}

在单独的线程中使用同步读取:

#include <thread>

void readThread()
{
    while(true)
    {
        //Will block until there is data to read
        boost::asio::read(tcpSocket, boost::asio::buffer(buffer, size));
    }
}


int main()
{

    std::string host = "192.168.1.3";
    std::string port = "8888";
    std::cout << "Attemping connection to host " << host << " on port " << port << std::endl;
    boost::asio::connect(tcpSocket, resolver.resolve({host, port}));
    std::cout << "Connected" << std::endl;

    std::thread r{readThread};

    return 0;
}

谢谢!请原谅我对asio和网络的经验不足:)

1 个答案:

答案 0 :(得分:3)

这主要是缩放问题。在ASIO中,io_service是您的中央I / O通知机制。它抽象了低级别的特定于操作系统的通知方法,如dev / epoll,I / O-Completion Ports和kqueue。

假设您要监控数千个同时连接以获取数据。如果为每个连接实现了一个具有一个线程的阻塞服务器,那么最终会有数千个线程,每个线程都需要一些资源开销。只是创建大致围绕系统中CPU数量的线程并让每个线程同时等待多个连接,这样做会更加高效。只有当您的读取操作是异步的时才能实现这一点,其中一个表示读取操作“在后台运行”,ASIO将在完成后通知您,以及有关哪个套接字完成的必要信息以及结果。这个模型被称为“主动”,它就像在WinSock中一样实现。

高吞吐量服务器可以看到异步读取的另一个原因,特别是对于WinSock,比同步读取更有效。在那里,有多个未完成的接收操作将锁定内核中的接收缓冲区,确保始终有可用于接收数据的空间而不必强制回退到内部接收缓冲区(例如SO_RCVBUF),如果已满,则会导致数据包丢失(UDP)或缩小TCP窗口,无论如何都会降低吞吐量。

Linux的工作方式不同(以反应方式),其中第二个原因不计算在内。但是,通知参数仍然存在。