C++ libuv 与 Boost/ASIO 相比如何?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11423426/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does libuv compare to Boost/ASIO?
提问by oberstet
I'd be interested in aspects like:
我会对以下方面感兴趣:
- scope/features
- performance
- maturity
- 范围/特征
- 表现
- 到期
回答by Tanner Sansbury
Scope
范围
Boost.Asiois a C++ library that started with a focus on networking, but its asynchronous I/O capabilities have been extended to other resources. Additionally, with Boost.Asio being part of the Boost libraries, its scope is slightly narrowed to prevent duplication with other Boost libraries. For example, Boost.Asio will not provide a thread abstraction, as Boost.Threadalready provides one.
Boost.Asio是一个 C++ 库,最初专注于网络,但其异步 I/O 功能已扩展到其他资源。此外,由于 Boost.Asio 是 Boost 库的一部分,它的范围略有缩小,以防止与其他 Boost 库重复。例如,Boost.Asio 不会提供线程抽象,因为Boost.Thread已经提供了一个。
On the other hand, libuvis a C library designed to be the platform layer for Node.js. It provides an abstraction for IOCPon Windows, kqueueon macOS, and epollon Linux. Additionally, it looks as though its scope has increased slightly to include abstractions and functionality, such as threads, threadpools, and inter-thread communication.
另一方面,libuv是一个 C 库,旨在成为Node.js的平台层。它为Windows上的IOCP、macOS上的kqueue和Linux 上的epoll提供了抽象。此外,它的范围似乎略有增加,以包括抽象和功能,例如线程、线程池和线程间通信。
At their core, each library provides an event loop and asynchronous I/O capabilities. They have overlap for some of the basic features, such as timers, sockets, and asynchronous operations. libuv has a broader scope, and provides additional functionality, such as thread and synchronization abstractions, synchronous and asynchronous file system operations, process management, etc. In contrast, Boost.Asio's original networking focus surfaces, as it provides a richer set of network related capabilities, such as ICMP, SSL, synchronous blocking and non-blocking operations, and higher-level operations for common tasks, including reading from a stream until a newline is received.
每个库的核心都提供事件循环和异步 I/O 功能。它们在一些基本功能上有重叠,例如定时器、套接字和异步操作。libuv 的范围更广,并提供了额外的功能,例如线程和同步抽象、同步和异步文件系统操作、进程管理等。相比之下,Boost.Asio 的原始网络焦点表面,因为它提供了一组更丰富的网络相关功能,例如 ICMP、SSL、同步阻塞和非阻塞操作,以及用于常见任务的更高级别的操作,包括从流中读取直到接收到换行符。
Feature List
功能列表
Here is the brief side-by-side comparison on some of the major features. Since developers using Boost.Asio often have other Boost libraries available, I have opted to consider additional Boost libraries if they are either directly provided or trivial to implement.
以下是一些主要功能的简要并排比较。由于使用 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.Extensionwas never submitted for review to Boost. As noted here, the author considers it to be complete.
2. Boost.Extension从未提交给 Boost 进行。正如这里所指出的,作者认为它是完整的。
Event Loop
事件循环
While both libuv and Boost.Asio provide event loops, there are some subtle differences between the two:
虽然 libuv 和 Boost.Asio 都提供事件循环,但两者之间存在一些细微差别:
- While libuv supports multiple event loops, it does not support running the same loop from multiple threads. For this reason, care needs to be taken when using the default loop (
uv_default_loop()
), rather than creating a new loop (uv_loop_new()
), as another component may be running the default loop. - Boost.Asio does not have the notion of a default loop; all
io_service
are their own loops that allow for multiple threads to run. To support this Boost.Asio performs internal lockingat the cost of some performance. Boost.Asio's revision historyindicates that there have been several performance improvements to minimize the locking.
- 虽然 libuv 支持多个事件循环,但它不支持从多个线程运行相同的循环。因此,在使用默认循环 (
uv_default_loop()
)时需要小心,而不是创建新循环 (uv_loop_new()
),因为另一个组件可能正在运行默认循环。 - Boost.Asio 没有默认循环的概念;一切
io_service
都是自己的循环,即允许多个线程运行。为了支持这个 Boost.Asio以牺牲一些性能为代价执行内部锁定。Boost.Asio 的修订历史表明,为了最大限度地减少锁定,已经进行了多项性能改进。
Threadpool
线程池
- libuv's provides a threadpool through
uv_queue_work
. The threadpool size is configurable via the environment variableUV_THREADPOOL_SIZE
. The work will be executed outside of the event loop and within the threadpool. Once the work is completed, the completion handler will be queued to run within the event loop. - While Boost.Asio does not provide a threadpool, the
io_service
can easily function as one as a result ofio_service
allowing multiple threads to invokerun
. This places the responsibility of thread management and behavior to the user, as can be seen in thisexample.
- libuv 通过
uv_queue_work
. 线程池大小可通过环境变量配置UV_THREADPOOL_SIZE
。工作将在事件循环之外和线程池内执行。一旦工作完成,完成处理程序将排队等待在事件循环内运行。 - 虽然 Boost.Asio 不提供线程池,但
io_service
由于io_service
允许多个线程调用run
. 这将线程管理和行为的责任交给用户,如本示例所示。
Threading and Synchronization
线程和同步
- libuv provides an abstraction to threads and synchronization types.
- Boost.Threadprovides a thread and synchronization types. Many of these types follow closely to the C++11 standard, but also provide some extensions. As a result of Boost.Asio allowing multiple threads to run a single event loop, it provides strandsas a means to create a sequential invocation of event handlers without using explicit locking mechanisms.
- libuv 提供了对线程和同步类型的抽象。
- Boost.Thread提供了线程和同步类型。其中许多类型都紧跟 C++11 标准,但也提供了一些扩展。由于 Boost.Asio 允许多个线程运行单个事件循环,因此它提供了链作为创建事件处理程序顺序调用的方法,而无需使用显式锁定机制。
File System Operations
文件系统操作
- libuv provides an abstraction to many file system operations. There is one function per operation, and each operation can either be synchronous blocking or asynchronous. If a callback is provided, then the operation will be executed asynchronously within an internal threadpool. If a callback is not provided, then the call will be synchronous blocking.
- Boost.Filesystemprovides synchronous blocking calls for many file system operations. These can be combined with Boost.Asio and a threadpool to create asynchronous file system operations.
- libuv 为许多文件系统操作提供了抽象。每个操作有一个函数,每个操作可以是同步阻塞或异步。如果提供了回调,则操作将在内部线程池中异步执行。如果未提供回调,则调用将被同步阻塞。
- Boost.Filesystem为许多文件系统操作提供同步阻塞调用。这些可以结合 Boost.Asio 和线程池来创建异步文件系统操作。
Networking
联网
- libuv supports asynchronous operations on UDP and TCP sockets, as well as DNS resolution. Application developers should be aware that the underlying file descriptors are set to non-blocking. Therefore, native synchronous operations should check return values and errnofor
EAGAIN
orEWOULDBLOCK
. - Boost.Asio is a bit more rich in its networking support. In addition many of the features libuv's networking provides, Boost.Asio supporting SSL and ICMP sockets. Furthermore, Boost.Asio provides synchronous blocking and synchronous non-blocking operations, into addition to its asynchronous operations. There are numerous free standing functions that provide common higher-level operations, such as reading a set amount of bytes, or until a specified delimiter character is read.
- libuv 支持对 UDP 和 TCP 套接字的异步操作,以及 DNS 解析。应用程序开发人员应该知道底层文件描述符被设置为非阻塞。因此,本地的同步操作应该检查返回值和错误号为
EAGAIN
或EWOULDBLOCK
。 - Boost.Asio 的网络支持更丰富一些。除了 libuv 网络提供的许多功能外,Boost.Asio 还支持 SSL 和 ICMP 套接字。此外,Boost.Asio 除了异步操作之外,还提供同步阻塞和同步非阻塞操作。有许多独立的函数提供常见的高级操作,例如读取一定数量的字节,或者直到读取指定的分隔符。
Signal
信号
- libuv provides an abstraction
kill
and signal handling with itsuv_signal_t
type anduv_signal_*
operations. - Boost.Asio does not provde an abstraction to
kill
, but itssignal_set
provides signal handling.
- libuv
kill
为其uv_signal_t
类型和uv_signal_*
操作提供了抽象和信号处理。 - Boost.Asio 不提供对 的抽象
kill
,但它signal_set
提供了信号处理。
IPC
工控机
- libuv abstracts Unix domain socketsand Windows named pipesthrough a single
uv_pipe_t
type. - Boost.Asio separates the two into
local::stream_protocol::socket
orlocal::datagram_protocol::socket
, andwindows::stream_handle
.
- libuv通过单一类型抽象Unix 域套接字和Windows 命名管道
uv_pipe_t
。 - Boost.Asio 将两者分为
local::stream_protocol::socket
orlocal::datagram_protocol::socket
, andwindows::stream_handle
。
API Differences
API 差异
While the APIs are different based on the language alone, here are a few key differences:
虽然 API 因语言而异,但以下是一些主要区别:
Operation and Handler Association
运营商协会
Within Boost.Asio, there is a one-to-one mapping between an operation and a handler. For instance, each async_write
operation will invoke the WriteHandleronce. This is true for many of libuv operations and handlers. However, libuv's uv_async_send
supports a many-to-one mapping. Multiple uv_async_send
calls may result in the uv_async_cbbeing called once.
在 Boost.Asio 中,操作和处理程序之间存在一对一的映射。例如,每个async_write
操作都会调用一次WriteHandler。许多 libuv 操作和处理程序都是如此。但是,libuvuv_async_send
支持多对一映射。多次uv_async_send
调用可能会导致uv_async_cb被调用一次。
Call Chains vs. Watcher Loops
调用链与观察者循环
When dealing with task, such as reading from a stream/UDP, handling signals, or waiting on timers, Boost.Asio's asynchronous call chains are a bit more explicit. With libuv, a watcher is created to designate interests in a particular event. A loop is then started for the watcher, where a callback is provided. Upon receiving the event of interests, the callback will be invoked. On the other hand, Boost.Asio requires an operation to be issued each time the application is interested in handling the event.
在处理任务时,例如从流/UDP 读取、处理信号或等待计时器,Boost.Asio 的异步调用链更加明确。使用 libuv,创建一个观察者来指定对特定事件的兴趣。然后为观察者启动一个循环,其中提供一个回调。收到感兴趣的事件后,将调用回调。另一方面,Boost.Asio 要求每次应用程序有兴趣处理事件时发出操作。
To help illustrate this difference, here is an asynchronous read loop with Boost.Asio, where the async_receive
call will be issued multiple times:
为了帮助说明这种差异,这里是一个使用 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 ); --'
}
And here is the same example with libuv, where handle_read
is invoked each time the watcher observes that the socket has data:
这是 libuv 的相同示例,handle_read
每次观察者观察到套接字有数据时都会调用where :
uv_read_start( socket, alloc_buffer, handle_read ); --.
|
.-------------------------------------------------'
|
V
void handle_read( ... )
{
fprintf( stdout, "got data\n" );
}
Memory Allocation
内存分配
As a result of the asynchronous call chains in Boost.Asio and the watchers in libuv, memory allocation often occurs at different times. With watchers, libuv defers allocation until after it receives an event that requires memory to handle. The allocation is done through a user callback, invoked internal to libuv, and defers deallocation responsibility of the application. On the other hand, many of the Boost.Asio operations require that the memory be allocated before issuing the asynchronous operation, such as the case of the buffer
for async_read
. Boost.Asio does provide null_buffers
, that can be used to listen for an event, allowing applications to defer memory allocation until memory is needed, although this is deprecated.
由于 Boost.Asio 中的异步调用链和 libuv 中的观察者,内存分配经常发生在不同的时间。对于观察者,libuv 将分配推迟到它接收到需要内存来处理的事件之后。分配是通过用户回调完成的,在 libuv 内部调用,并推迟应用程序的释放责任。另一方面,许多 Boost.Asio 操作要求在发出异步操作之前分配内存,例如buffer
for的情况async_read
。Boost.Asio 确实提供了null_buffers
,可用于侦听事件,允许应用程序将内存分配推迟到需要内存时,尽管这已被弃用。
This memory allocation difference also presents itself within the bind->listen->accept
loop. With libuv, uv_listen
creates an event loop that will invoke the user callback when a connection is ready to be accepted. This allows the application to defer the allocation of the client until a connection is being attempted. On the other hand, Boost.Asio's listen
only changes the state of the acceptor
. The async_accept
listens for the connection event, and requires the peer to be allocated before being invoked.
这种内存分配差异也出现在bind->listen->accept
循环中。使用 libuv,uv_listen
创建一个事件循环,当连接准备好被接受时,它将调用用户回调。这允许应用程序推迟客户端的分配,直到尝试连接。另一方面,Boost.Asiolisten
只会改变acceptor
. 该async_accept
用于连接事件监听,并要求对方在被调用之前进行分配。
Performance
表现
Unfortunately, I do not have any concrete benchmark numbers to compare libuv and Boost.Asio. However, I have observed similar performance using the libraries in real-time and near-real-time applications. If hard numbers are desired, libuv's benchmark testmay serve as a starting point.
不幸的是,我没有任何具体的基准数字来比较 libuv 和 Boost.Asio。但是,我在实时和近实时应用程序中使用这些库观察到类似的性能。如果需要硬数字,libuv 的基准测试可以作为起点。
Additionally, while profiling should be done to identify actual bottlenecks, be aware of memory allocations. For libuv, the memory allocation strategy is primarily limited to the allocator callback. On the other hand, Boost.Asio's API does not allow for an allocator callback, and instead pushes the allocation strategy to the application. However, the handlers/callbacks in Boost.Asio may be copied, allocated, and deallocated. Boost.Asio allows for applications to provide custom memory allocationfunctions in order to implement a memory allocation strategy for handlers.
此外,虽然应该进行分析以识别实际瓶颈,但请注意内存分配。对于 libuv,内存分配策略主要限于分配器回调。另一方面,Boost.Asio 的 API 不允许分配器回调,而是将分配策略推送给应用程序。但是,Boost.Asio 中的处理程序/回调可以被复制、分配和解除分配。Boost.Asio 允许应用程序提供自定义内存分配函数,以便为处理程序实现内存分配策略。
Maturity
到期
Boost.Asio
Boost.Asio
Asio's development dates back to at least OCT-2004, and it was accepted into Boost 1.35 on 22-MAR-2006 after undergoing a 20-day peer review. It also served as the reference implementation and API for Networking Library Proposal for TR2. Boost.Asio has a fair amount of documentation, although its usefulness varies from user to user.
Asio 的开发至少可以追溯到 OCT-2004,经过 20 天的同行评审后,它于 2006 年 3 月 22 日被 Boost 1.35 接受。它还用作 TR2 网络库提案的参考实现和 API 。Boost.Asio 有相当数量的文档,尽管它的用处因用户而异。
The API also have a fairly consistent feel. Additionally, the asynchronous operations are explicit in the operation's name. For example, accept
is synchronous blocking and async_accept
is asynchronous. The API provides free functions for common I/O task, for instance, reading from a stream until a \r\n
is read. Attention has also been given to hide some network specific details, such as the ip::address_v4::any()
representing the "all interfaces" address of 0.0.0.0
.
API 也具有相当一致的感觉。此外,异步操作在操作名称中是显式的。例如,accept
是同步阻塞和async_accept
异步。API 为常见 I/O 任务提供免费功能,例如从流\r\n
中读取直到读取 a。还注意隐藏一些特定于网络的细节,例如ip::address_v4::any()
表示0.0.0.0
.
Finally, Boost 1.47+ provides handler tracking, which can prove to be useful when debugging, as well as C++11 support.
最后,Boost 1.47+ 提供了处理程序跟踪,这在调试时证明是有用的,以及 C++11 支持。
libuv
libuv
Based on their github graphs, Node.js's development dates back to at least FEB-2009, and libuv's development dates to MAR-2011. The uvbookis a great place for a libuv introduction. The API documentation is here.
根据他们的 github 图,Node.js 的开发日期至少可以追溯到FEB-2009,而 libuv 的开发日期可以追溯到MAR-2011。该uvbook是一个libuv引进一个伟大的地方。API 文档在这里。
Overall, the API is fairly consistent and easy to use. One anomaly that may be a source of confusion is that uv_tcp_listen
creates a watcher loop. This is different than other watchers that generally have a uv_*_start
and uv_*_stop
pair of functions to control the life of the watcher loop. Also, some of the uv_fs_*
operations have a decent amount of arguments (up to 7). With the synchronous and asynchronous behavior being determined on the presence of a callback (the last argument), the visibility of the synchronous behavior can be diminished.
总体而言,该 API 相当一致且易于使用。一个可能引起混淆的异常是uv_tcp_listen
创建观察者循环。这比通常具有其他观察者不同uv_*_start
和uv_*_stop
对函数来控制所述观察者环的寿命。此外,一些uv_fs_*
操作有相当数量的参数(最多 7 个)。通过根据回调(最后一个参数)的存在来确定同步和异步行为,同步行为的可见性可能会降低。
Finally, a quick glance at the libuv commit historyshows that the developers are very active.
最后,快速浏览一下 libuv提交历史表明开发人员非常活跃。
回答by Oleksandr Karaberov
Ok. I have some experience in using both libraries and can clearify some things.
好的。我在使用这两个库方面都有一些经验,可以澄清一些事情。
First, from a conceptual view-point these libraries are quite different in design. They have different architectures, because they are of different scale. Boost.Asio is a large networking library aimed to be used with TCP/UDP/ICMP protocols, POSIX, SSL and so on. Libuv is just a layer for cross-platform abstraction of IOCPfor Node.js, predominantly. So libuv is functionally a subset of Boost.Asio (common features only TCP/UDP Sockets threads,timers). Being that the case, we can compare these libraries using only few criteria:
首先,从概念的角度来看,这些库在设计上有很大的不同。它们具有不同的架构,因为它们的规模不同。Boost.Asio 是一个大型网络库,旨在与 TCP/UDP/ICMP 协议、POSIX、SSL 等一起使用。Libuv 只是一个主要用于 Node.js IOCP跨平台抽象的层。所以 libuv 在功能上是 Boost.Asio 的一个子集(常见功能只有 TCP/UDP Sockets 线程、定时器)。在这种情况下,我们可以只使用几个标准来比较这些库:
- Integration with Node.js - Libuv is considerably better because it is aimed for this (we can fully integrate it and use in all aspects, for instance, cloud e.g. windows azure). But Asio also implements almost the same functionality as in Node.js event queue driven environment.
- IOCP Performance - I couldn't see great differencies, because both these libraries abstract underlying OS API. But they do it in a different way: Asio heavily uses C++ features such as templates and sometimes TMP. Libuv is a native C-library. But nevertheless Asio realisation of IOCP is very efficient. UDP sockets in Asio are not good enough it is better to use libuv for them.
Integration with new C++ features: Asio is better (Asio 1.51 extensively use C++11 asynchronous model, move semantics, variadic templates).In regard to maturity, Asio is a more stable and mature project with good documentation (if compare it to libuv headers description), a lot of information across the Internet (video talks, blogs: http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=1,etc.) and even books (not for professionals but nevertheless: http://en.highscore.de/cpp/boost/index.html). Libuv has only one online book (but also good) http://nikhilm.github.com/uvbook/index.htmland several video talks, so it will be difficult to know all the secrets (this library has a lot of them). For more specific discussion of functions see my comments below.
- 与 Node.js 的集成 - Libuv 明显更好,因为它是针对此目标的(我们可以完全集成它并在所有方面使用,例如,云,例如 windows azure)。但是 Asio 也实现了与 Node.js 事件队列驱动环境几乎相同的功能。
- 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和几个视频谈话,所以很难知道所有的秘密(这个图书馆有很多)。有关函数的更具体讨论,请参阅下面我的评论。
As conclusion, I should said that it all depends on your purposes, your project and what concretely you intend to do.
作为结论,我应该说这完全取决于您的目的,您的项目以及您具体打算做什么。
回答by Vinnie Falco
One huge difference is the author of Asio (Christopher Kohlhoff) is grooming his library for inclusion in the C++ Standard Library, see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2175.pdfand http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4370.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
回答by kakyo
Adding the portability status: As of posting this answer and according to my own attempts:
添加可移植性状态:截至发布此答案并根据我自己的尝试:
- Boost.ASIO has no official support for iOS and Android, e.g., its build system does not work for iOS out of the box.
- libuv builds easily for iOS and Android, with official support for Android right in their docs. My own generic iOS build script for Autotools-based projects works without issues.
- Boost.ASIO 没有对 iOS 和 Android 的官方支持,例如,它的构建系统不适用于 iOS 开箱即用。
- libuv 可以轻松地为 iOS 和 Android 构建,在他们的文档中提供对 Android 的官方支持。我自己的基于 Autotools 的项目的通用 iOS 构建脚本可以正常工作。