我会对以下方面感兴趣:
- 范围/功能
- 表现
- 到期
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 都提供事件循环,但两者之间存在一些细微差别:
uv_default_loop()
) 时需要小心,而不是创建新循环 ( uv_loop_new()
),因为另一个组件可能正在运行默认循环。io_service
它们自己的循环,允许多个线程运行。为了支持这一点,Boost.Asio以牺牲一些性能为代价执行内部锁定。Boost.Asio 的修订历史表明已经进行了多项性能改进以最小化锁定。uv_queue_work
. 线程池大小可通过环境变量进行配置UV_THREADPOOL_SIZE
。该工作将在事件循环之外和线程池内执行。一旦工作完成,完成处理程序将在事件循环中排队运行。io_service
可以很容易地作为一个线程池运行。这将线程管理和行为的责任交给用户,如本例所示。io_service
run
EAGAIN
EWOULDBLOCK
kill
和信号处理。uv_signal_t
uv_signal_*
kill
,但它signal_set
提供信号处理。uv_pipe_t
local::stream_protocol::socket
orlocal::datagram_protocol::socket
和windows::stream_handle
。虽然 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 操作要求在发出异步操作之前分配内存,例如buffer
for的情况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 允许应用程序提供自定义内存分配函数,以便为处理程序实现内存分配策略。
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-2011。uvbook是介绍libuv的好地方。API 文档在这里。
总体而言,API 相当一致且易于使用。一个可能引起混淆的异常是uv_tcp_listen
创建了一个观察者循环。这与其他通常具有一uv_*_start
对uv_*_stop
函数来控制观察者循环生命周期的观察者不同。此外,一些uv_fs_*
操作有相当数量的参数(最多 7 个)。通过回调(最后一个参数)的存在来确定同步和异步行为,可以减少同步行为的可见性。
最后,快速浏览一下 libuv提交历史会发现开发人员非常活跃。
好的。我在使用这两个库方面都有一些经验,可以澄清一些事情。
首先,从概念的角度来看,这些库的设计完全不同。它们具有不同的架构,因为它们具有不同的规模。Boost.Asio 是一个大型网络库,旨在与 TCP/UDP/ICMP 协议、POSIX、SSL 等一起使用。Libuv 只是主要用于 Node.js的IOCP的跨平台抽象层。所以 libuv 在功能上是 Boost.Asio 的一个子集(通用功能只有 TCP/UDP 套接字线程、定时器)。既然如此,我们可以只使用几个标准来比较这些库:
与 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和几个视频谈话,所以很难知道所有的秘密(这个图书馆有很多)。有关功能的更具体讨论,请参阅下面的评论。
作为结论,我应该说这完全取决于您的目的,您的项目以及您打算做什么。
一个巨大的不同是 Asio 的作者 (Christopher Kohlhoff) 正在整理他的库以包含在 C++ 标准库中,请参阅http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2175 .pdf和http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4370.html
添加可移植性状态:截至发布此答案并根据我自己的尝试: