264

我会对以下方面感兴趣:

  • 范围/功能
  • 表现
  • 到期
4

4 回答 4

537

范围

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 + Threads
穿线:              
  线程:是的
  同步:是线程
文件系统操作:
  同步:是文件系统
  异步:是 Asio + 文件系统
计时器:是的
分散/聚集 I/O [1] : 无 Asio
联网:
  ICMP:没有 Asio
  DNS 解析:仅异步 Asio
  SSL:没有 Asio
  TCP:仅异步 Asio
  UDP:仅异步 Asio
信号:
  处理:是的
  发送:是 否
工控机:
  UNIX 域套接字:是 Asio
  Windows 命名管道:是 Asio
流程管理:
  分离:是过程
  I/O 管道:是 进程
  产卵:是过程
系统查询:
  中央处理器:是 否
  网络接口:是 否
串行端口:否 是
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_servicerun

线程和同步

  • libuv 提供了对线程和同步类型的抽象。
  • Boost.Thread提供了线程和同步类型。这些类型中的许多类型都严格遵循 C++11 标准,但也提供了一些扩展。由于 Boost.Asio 允许多个线程运行单个事件循环,它提供了strands作为创建事件处理程序的顺序调用的一种方法,而无需使用显式锁定机制。

文件系统操作

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

联网

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

信号

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

工业PC


API 差异

虽然 API 仅基于语言而有所不同,但这里有一些主要区别:

操作和处理程序关联

在 Boost.Asio 中,操作和处理程序之间存在一对一的映射。例如,每个async_write操作都会调用一次WriteHandler。许多 libuv 操作和处理程序都是如此。但是,libuvuv_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每次观察者观察到套接字有数据时都会调用 where:

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

内存分配

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

这种内存分配差异也出现在bind->listen->accept循环中。使用 libuv,uv_listen创建一个事件循环,当连接准备好被接受时将调用用户回调。这允许应用程序延迟分配客户端,直到尝试连接。另一方面,Boost.Asiolisten只改变acceptor. 侦听连接事件,并要求在async_accept调用之前分配对等方。


表现

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

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


到期

Boost.Asio

Asio 的开发至少可以追溯到 OCT-2004,经过 20 天的同行评审后,它于 2006 年 3 月 22 日被 Boost 1.35 接受。它还用作 TR2 的 Networking Library Proposal的参考实现和 API 。Boost.Asio 有大量的文档,尽管它的用处因用户而异。

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

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

库夫

根据他们的 github 图,Node.js 的开发至少可以追溯到FEB-2009,而 libuv 的开发可以追溯到MAR-2011uvbook是介绍libuv的好地方。API 文档在这里

总体而言,API 相当一致且易于使用。一个可能引起混淆的异常是uv_tcp_listen创建了一个观察者循环。这与其他通常具有一uv_*_startuv_*_stop函数来控制观察者循环生命周期的观察者不同。此外,一些uv_fs_*操作有相当数量的参数(最多 7 个)。通过回调(最后一个参数)的存在来确定同步和异步行为,可以减少同步行为的可见性。

最后,快速浏览一下 libuv提交历史会发现开发人员非常活跃。

于 2012-11-04T16:38:29.617 回答
49

好的。我在使用这两个库方面都有一些经验,可以澄清一些事情。

首先,从概念的角度来看,这些库的设计完全不同。它们具有不同的架构,因为它们具有不同的规模。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和几个视频谈话,所以很难知道所有的秘密(这个图书馆有很多)。有关功能的更具体讨论,请参阅下面的评论。

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

于 2012-10-30T12:27:15.747 回答
23

一个巨大的不同是 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

于 2016-03-25T14:36:57.210 回答
2

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

  • Boost.ASIO 没有对 iOS 和 Android 的官方支持,例如,它的构建系统不适用于开箱即用的 iOS。
  • libuv 可以轻松地为 iOS 和 Android 构建,并在其文档中对 Android 提供官方支持。我自己的基于 Autotools 的项目的通用 iOS 构建脚本可以正常工作。
于 2019-10-20T04:14:00.290 回答