libuv与Boost/ASIO相比如何?

obe*_*tet 221 c++ boost boost-asio libuv

我会对以下方面感兴趣:

  • 范围/功能
  • 性能
  • 到期

Tan*_*ury 475

范围

Boost.Asio是一个C++库,首先关注网络,但其异步I/O功能已经扩展到其他资源.此外,Boost.Asio是Boost库的一部分,其范围略有缩小,以防止与其他Boost库重复.例如,Boost.Asio不会提供线程抽象,因为Boost.Thread已经提供了一个.

另一方面,libuv是一个C库,旨在成为Node.js的平台层.它为Windows 上的IOCP,macOS 上的kqueue和Linux上的epoll提供了抽象.此外,看起来它的范围略有增加,包括抽象和功能,如线程,线程池和线程间通信.

每个库的核心是提供事件循环和异步I/O功能.它们与某些基本功能重叠,例如定时器,套接字和异步操作.libuv具有更广泛的范围,并提供额外的功能,如线程和同步抽象,同步和异步文件系统操作,进程管理等.相比之下,Boost.Asio的原始网络焦点表面,因为它提供了更丰富的网络相关集功能,例如ICMP,SSL,同步阻塞和非阻塞操作,以及常见任务的更高级别操作,包括从流中读取直到收到换行符.


功能列表

以下是一些主要功能的简要并列比较.由于使用Boost.Asio的开发人员通常可以使用其他Boost库,因此我选择考虑使用其他Boost库,如果它们是直接提供的,或者是实现的那么简单.

                         libuv          Boost
Event Loop:              yes            Asio
Threadpool:              yes            Asio + Threads
Threading:              
  Threads:               yes            Threads
  Synchronization:       yes            Threads
File System Operations:
  Synchronous:           yes            FileSystem
  Asynchronous:          yes            Asio + Filesystem
Timers:                  yes            Asio
Scatter/Gather I/O[1]:    no             Asio
Networking:
  ICMP:                  no             Asio
  DNS Resolution:        async-only     Asio
  SSL:                   no             Asio
  TCP:                   async-only     Asio
  UDP:                   async-only     Asio
Signal:
  Handling:              yes            Asio
  Sending:               yes            no
IPC:
  UNIX Domain Sockets:   yes            Asio
  Windows Named Pipe:    yes            Asio
Process Management:
  Detaching:             yes            Process
  I/O Pipe:              yes            Process
  Spawning:              yes            Process
System Queries:
  CPU:                   yes            no
  Network Interface:     yes            no
Serial Ports:            no             yes
TTY:                     yes            no
Shared Library Loading:  yes            Extension[2]

1. 分散/聚集I/O.

2. Boost.Extension从未提交给Boost进行审核.如前所述这里,笔者认为它是完整的.

事件循环

虽然libuv和Boost.Asio都提供了事件循环,但两者之间存在一些细微差别:

  • 虽然libuv支持多个事件循环,但它不支持从多个线程运行相同的循环.因此,在使用默认循环(uv_default_loop())时需要注意,而不是创建新的循环(uv_loop_new()),因为另一个组件可能正在运行默认循环.
  • Boost.Asio没有默认循环的概念; 所有io_service都是他们自己的循环,允许多个线程运行.为了支持这个Boost.Asio以一些性能为代价执行内部锁定.Boost.Asio的修订历史表明,已经进行了一些性能改进以最小化锁定.

线程池

  • libuv提供了一个线程池uv_queue_work.线程池大小可通过环境变量进行配置UV_THREADPOOL_SIZE.该工作将在事件循环之外和线程池内执行.工作完成后,完成处理程序将排队等待在事件循环中运行.
  • 虽然Boost.Asio不提供线程池,但io_service由于io_service允许多个线程调用,因此可以很容易地作为一个线程池运行run.这将线程管理和行为的责任交给用户,如例所示.

线程和同步

  • libuv为线程和同步类型提供了抽象.
  • Boost.Thread提供了线程和同步类型.其中许多类型都遵循C++ 11标准,但也提供了一些扩展.作为Boost.Asio的的允许多个线程运行单个事件循环的结果,它提供了股线,以创建事件处理程序的顺序的调用,而不使用显式锁定机构的装置.

文件系统操作

  • libuv为许多文件系统操作提供了抽象.每个操作有一个功能,每个操作可以是同步阻塞或异步.如果提供了回调,则操作将在内部线程池中异步执行.如果未提供回调,则呼叫将是同步阻止.
  • Boost.Filesystem为许多文件系统操作提供同步阻塞调用.这些可以与Boost.Asio和线程池结合使用来创建异步文件系统操作.

联网

  • libuv支持UDP和TCP套接字上的异步操作,以及DNS解析.应用程序开发人员应该知道底层文件描述符设置为非阻塞.因此,本机同步操作应检查返回值和errno for EAGAINEWOULDBLOCK.
  • Boost.Asio的网络支持更加丰富.此外,libuv的网络提供了许多功能,Boost.Asio支持SSL和ICMP套接字.此外,除了异步操作之外,Boost.Asio还提供同步阻塞和同步非阻塞操作.有许多独立的函数可以提供常见的高级操作,例如读取一定量的字节,或者直到读取指定的分隔符.

信号

  • libuv提供了类型和操作的抽象kill和信号处理.uv_signal_tuv_signal_*
  • Boost.Asio不提供抽象kill,但它signal_set提供信号处理.

IPC


API差异

虽然API仅根据语言而有所不同,但以下是一些主要差异:

运营和处理协会

在Boost.Asio中,操作和处理程序之间存在一对一的映射.例如,每个async_write操作都会调用一次WriteHandler.许多libuv操作和处理程序都是如此.但是,libuv uv_async_send支持多对一映射.多次uv_async_send调用可能导致uv_async_cb被调用一次.

呼叫链与观察者循环

在处理任务时,例如从流/ UDP读取,处理信号或等待定时器,Boost.Asio的异步调用链更加明确.使用libuv,创建观察者以指定对特定事件的兴趣.然后为观察者启动循环,其中提供回调.收到兴趣事件后,将调用回调.另一方面,Boost.Asio要求每次应用程序有兴趣处理事件时发出操作.

为了帮助说明这种差异,这里是一个带Boost.Asio的异步读循环,其中async_receive调用将多次发出:

void start()
{
  socket.async_receive( buffer, handle_read ); ----.
}                                                  |
    .----------------------------------------------'
    |      .---------------------------------------.
    V      V                                       |
void handle_read( ... )                            |
{                                                  |
  std::cout << "got data" << std::endl;            |
  socket.async_receive( buffer, handle_read );   --'
}    
Run Code Online (Sandbox Code Playgroud)

以下是与libuv相同的示例,handle_read每次观察者观察到套接字有数据时都会调用它:

uv_read_start( socket, alloc_buffer, handle_read ); --.
                                                      |
    .-------------------------------------------------'
    |
    V
void handle_read( ... )
{
  fprintf( stdout, "got data\n" );
}
Run Code Online (Sandbox Code Playgroud)

内存分配

由于Boost.Asio中的异步调用链和libuv中的观察者,内存分配通常在不同时间发生.对于观察者,libuv推迟分配,直到它收到需要内存处理的事件.分配是通过用户回调完成的,在libuv内部调用,并延迟应用程序的释放责任.另一方面,许多Boost.Asio操作要求在发出异步操作之前分配内存,例如bufferfor 的情况async_read.Boost.Asio确实提供null_buffers了可用于侦听事件,允许应用程序推迟内存分配直到需要内存,尽管这已被弃用.

这种内存分配差异也表现在bind->listen->accept循环内.使用libuv,uv_listen创建一个事件循环,当连接准备好被接受时,它将调用用户回调.这允许应用程序推迟客户端的分配,直到尝试连接.另一方面,Boost.Asio listen只改变了状态acceptor.该async_accept用于连接事件监听,并要求对方在被调用之前进行分配.


性能

不幸的是,我没有任何具体的基准数字来比较libuv和Boost.Asio.但是,我观察到在实时和近实时应用程序中使用库的类似性能.如果需要硬数字,libuv的基准测试可以作为起点.

此外,虽然应该进行性能分析以识别实际瓶颈,但要注意内存分配.对于libuv,内存分配策略主要限于分配器回调.另一方面,Boost.Asio的API不允许分配器回调,而是将分配策略推送到应用程序.但是,Boost.Asio中的处理程序/回调可能会被复制,分配和释放.Boost.Asio允许应用程序提供自定义内存分配功能,以便为处理程序实现内存分配策略.


到期

Boost.Asio的

Asio的发展至少可以追溯到2004年的OCT-2004,经过为期20天的同行评审后,它在2006年3月22日的Boost 1.35被接受​​.它还作为TR2网络库提案的参考实现和API .Boost.Asio有相当数量的文档,尽管其用途因用户而异.

API也具有相当一致的感觉.此外,异步操作在操作名称中是显式的.例如,accept是同步阻塞并且async_accept是异步的.API为常见的I/O任务提供免费功能,例如,从流\r\n中读取直到读取.还注意隐藏一些网络特定的细节,例如ip::address_v4::any()表示"所有接口"的地址0.0.0.0.

最后,Boost 1.47+提供了处理程序跟踪,这可以证明在调试时很有用,以及C++ 11支持.

libuv

根据他们的github图,Node.js的开发可以追溯到至少FEB-2009,libuv的开发日期可以追溯到2011年3月.该uvbook是一个libuv引进一个伟大的地方.API文档在这里.

总的来说,API相当一致且易于使用.可能是混淆源的一个异常是uv_tcp_listen创建观察者循环.这比通常具有其他观察者不同uv_*_startuv_*_stop对函数来控制所述观察者环的寿命.此外,一些uv_fs_*操作具有相当数量的参数(最多7个).在存在回调(最后一个参数)的情况下确定同步和异步行为时,可以减少同步行为的可见性.

最后,快速浏览libuv 提交历史记录表明开发人员非常活跃.

  • 难以置信的答案.这包括高级图片,以及细节上的具体,重要差异(如线程/事件循环).非常感谢你! (26认同)
  • 谢啦!很好的答案!我想不出更全面的东西:) (2认同)
  • 从性能角度来看,Boost.Asio上事件循环的内部锁定看起来很可怕.它如何与无锁libuv具有相似的性能?也许在性能部分添加警告声明可能会有所帮助. (2认同)

Ole*_*rov 45

好.我有使用这两个库的经验,可以清除一些东西.

首先,从概念的角度来看,这些库的设计完全不同.它们具有不同的架构,因为它们具有不同的规模.Boost.Asio是一个大型网络库,旨在与TCP/UDP/ICMP协议,POSIX,SSL等一起使用.Libuv只是Node.js 的IOCP跨平台抽象层,主要是.所以libuv在功能上是Boost.Asio的子集(常见功能只有TCP/UDP套接字线程,定时器).就是这样,我们可以使用几个标准来比较这些库:

  1. 与Node.js集成 - Libuv相当好,因为它针对此(我们可以完全集成它并在所有方面使用,例如,云,例如windows azure).但Asio也实现了与Node.js事件队列驱动环境几乎相同的功能.
  2. IOCP性能 - 我看不出很大差异,因为这两个库都抽象了底层的OS API.但他们以不同的方式做到这一点:Asio大量使用C++功能,如模板,有时使用TMP.Libuv是一个原生的C库.但是,Asio实现IOCP非常有效.Asio中的UDP套接字不够好,最好为它们使用libuv.

    与新的C++特性集成:Asio更好(Asio 1.51广泛使用C++ 11异步模型,移动语义,可变参数模板).在成熟度方面,Asio是一个更稳定,更成熟的项目,具有良好的文档(如果将其与libuv进行比较)标题描述),互联网上的大量信息(视频讲座,博客:http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio? pg = 1,等等甚至书籍(不是专业人士,但仍然是:http://en.highscore.de/cpp/boost/index.html).Libuv只有一本在线书籍(但也很好)http://nikhilm.github.com/uvbook/index.html和几个视频会谈,所以很难知道所有的秘密(这个库有很多).有关函数的更具体讨论,请参阅下面的评论.

作为结论,我应该说这完全取决于你的目的,你的项目以及你打算做什么.

  • 重要的是您的技术技能和经验.来自古巴的亲切问候. (11认同)
  • @AlexanderKaraberov你能否扩展ASIO对UDP的问题? (6认同)
  • 除了Asio的文档,我同意你的所有观点.官方文档对这个精彩的图书馆没有任何正义.还有很多其他的文档和作者提出的一个强调谈话,我发现它非常有用.我没有遇到过Asio的书.你可以在答案中链接吗?这将非常有帮助. (2认同)

Vin*_*lco 16

一个巨大的区别是Asio(Christopher Kohlhoff)的作者正在修饰他的图书馆以包含在C++标准库中,参见http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2175 .pdfhttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4370.html