2017-10-29 196 views
2

我很好奇,如果在Boost ASIO中使用异步读取功能相比于使用单独读取同步的线程有任何性能优势。用例将不得不始终监听来自远程主机的数据。Boost async_read vs阻塞同步线程 - 性能差异?

在异步情况下,我相信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和网络的经验不足:)

+0

网络是速率决定步骤。你用哪个API来驱动它几乎是不相关的。 – EJP

回答

2

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

假设您想要监视数千个并发连接以处理数据。如果您为每个连接使用一个线程实现了一个阻塞服务器,则最终会有数千个线程,每个线程都会占用一些资源开销。只是大致围绕系统中的CPU数量创建线程,并让每个线程同时等待多个连接,这将会更加高效。这只有在读操作是异步的时候才能实现,其中一个说读操作“在后台运行”,并且ASIO会在完成时通知你,以及关于哪个套接字完成了什么结果的必要信息。这种模式被称为“积极主动”,它在WinSock中就是这样实现的。

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

Linux的工作方式不同(以被动方式),其中第二个原因不计算在内。然而,通知论证仍然成立。