libuv与Boost / ASIO相比如何?


Answers:


493

范围

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加速
事件循环:是Asio
线程池:是Asio +线程
线程:              
  线程:是的线程
  同步:是线程
文件系统操作:
  同步:是FileSystem
  异步:是Asio +文件系统
计时器:是的Asio
分散/聚集I / O [1]:无Asio
联网:
  ICMP:没有Asio
  DNS解析:仅异步Asio
  SSL:无Asio
  TCP:仅异步Asio
  UDP:仅异步Asio
信号:
  处理:是Asio
  发送:是否
IPC:
  UNIX域套接字:是Asio
  Windows命名管道:是Asio
流程管理:
  拆卸:是的过程
  I / O管道:是进程
  产生:是的过程
系统查询:
  CPU:是否
  网络接口:是否
串行端口:否是
TTY:是的
共享库加载:是扩展[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解析。应用程序开发人员应注意,基础文件描述符已设置为非阻塞。因此,本地的同步操作应该检查返回值和错误号EAGAINEWOULDBLOCK
  • Boost.Asio在网络支持方面更加丰富。除了libuv网络提供的许多功能外,Boost.Asio还支持SSL和ICMP套接字。此外,Boost.Asio除了其异步操作之外,还提供了同步阻止和同步非阻止操作。有许多独立功能可提供常见的高级操作,例如读取一定数量的字节,或者直到读取指定的分隔符。

信号

  • libuv kill通过其uv_signal_t类型和uv_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 );   --'
}    

这是libuv的相同示例,handle_read每次观察者观察到套接字具有数据时都会调用该示例:

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

内存分配

由于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年10月,并且在经过20天的同行评审之后,于2006年3月22日被Boost 1.35接受。它还用作TR2网络图书馆提案的参考实现和API 。Boost.Asio具有大量文档,尽管其实用性因用户而异。

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

最后,Boost 1.47+提供了处理程序跟踪,它在调试以及C ++ 11支持时都非常有用。

libuv

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

总体而言,该API相当一致且易于使用。可能引起混乱的一个异常是uv_tcp_listen创建观察者循环。这不同于通常具有uv_*_startuv_*_stop对功能来控制观察程序循环寿命的其他观察程序。同样,某些uv_fs_*操作具有相当数量的参数(最多7个)。通过根据回调(最后一个参数)的存在确定同步和异步行为,可以减少同步行为的可见性。

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


2
谢啦!好答案!我想不出更全面的方法了:)
越南

1
我对答案非常满意,我将悬赏奖励给您:)让SO自己决定最佳答案。
2012年

28
难以置信的答案。这既涵盖了高级情况,又涵盖了具体的重要细​​节差异(例如,线程/事件循环)。非常感谢你!
oberstet 2012年

1
@oberstet:不。我已经更新了答案,以提及libuv的大多数操作都是一对一的。但是,libuv可以累积多个uv_async_send调用,并通过单个回调处理所有这些调用。它记录在这里。另外,谢谢大家。
Tanner Sansbury

2
从性能的角度来看,Boost.Asio上事件循环的内部锁定看起来很可怕。它如何具有与无锁libuv相似的性能?也许在效果部分添加警告说明可能会有所帮助。
zeodtr 2014年

46

好。我在使用这两个库方面都有一定的经验,可以解决一些问题。

首先,从概念上来看,这些库在设计上有很大的不同。它们具有不同的体系结构,因为它们的规模不同。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库。但是,尽管如此,IOCP的Asio实现还是非常有效的。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
重要的是您的技术技能和经验。来自古巴的亲切问候。
2012年

2
除Asio的文档外,我同意您的所有观点。官方文档并没有对这个美妙的图书馆产生任何影响。我发现还有很多其他文档和作者的提升意见非常有用。而且我还没有读过有关Asio的书。您可以在答案中链接吗?这将非常有帮助。
维卡斯2012年

@vikas是的,我同意文档很差,有时会相互矛盾,但是与libuv相比,它是入门的好方法。至于书,我编辑了我的答案,但我想您已经看过(不幸的是,没有一本书专门针对Boost编写,只是分散了信息)
Oleksandr Karaberov 2012年

您的意思是“所以libuv在功能上是Boost.Asio的子集(TCP / UDP /套接字和线程)”?据TOC nikhilm.github.com/uvbook/index.html称, libuv具有更广泛的应用,然后是boost :: asio。
谢尔盖·尼古洛夫

7
@AlexanderKaraberov您能否扩展ASIO与UDP有关的问题?
布鲁诺·马丁内斯


2

添加可移植性状态:截至发布此答案并根据我自己的尝试:

  • Boost.ASIO没有对iOS和Android的官方支持,例如,其构建系统不适用于现成的iOS。
  • libuv可以在iOS和Android上轻松构建,并在其文档中直接支持Android 。我自己的用于基于Autotools的项目的通用iOS构建脚本可以正常工作。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.