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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:08:29  来源:igfitidea点击:

How does libuv compare to Boost/ASIO?

c++boostboost-asiolibuv

提问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. Scatter/Gather I/O.

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_serviceare 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 variable UV_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_servicecan easily function as one as a result of io_serviceallowing multiple threads to invoke run. 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 EAGAINor EWOULDBLOCK.
  • 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 解析。应用程序开发人员应该知道底层文件描述符被设置为非阻塞。因此,本地的同步操作应该检查返回值和错误号EAGAINEWOULDBLOCK
  • Boost.Asio 的网络支持更丰富一些。除了 libuv 网络提供的许多功能外,Boost.Asio 还支持 SSL 和 ICMP 套接字。此外,Boost.Asio 除了异步操作之外,还提供同步阻塞和同步非阻塞操作。有许多独立的函数提供常见的高级操作,例如读取一定数量的字节,或者直到读取指定的分隔符。

Signal

信号

  • libuv provides an abstraction killand signal handling with its uv_signal_ttype and uv_signal_*operations.
  • Boost.Asio does not provde an abstraction to kill, but its signal_setprovides signal handling.
  • libuvkill为其uv_signal_t类型和uv_signal_*操作提供了抽象和信号处理。
  • Boost.Asio 不提供对 的抽象kill,但它signal_set提供了信号处理。

IPC

工控机



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_writeoperation will invoke the WriteHandleronce. This is true for many of libuv operations and handlers. However, libuv's uv_async_sendsupports a many-to-one mapping. Multiple uv_async_sendcalls 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_receivecall 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_readis 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 bufferfor 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 操作要求在发出异步操作之前分配内存,例如bufferfor的情况async_read。Boost.Asio 确实提供了null_buffers,可用于侦听事件,允许应用程序将内存分配推迟到需要内存时,尽管这已被弃用。

This memory allocation difference also presents itself within the bind->listen->acceptloop. With libuv, uv_listencreates 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 listenonly changes the state of the acceptor. The async_acceptlistens 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, acceptis synchronous blocking and async_acceptis asynchronous. The API provides free functions for common I/O task, for instance, reading from a stream until a \r\nis 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_listencreates a watcher loop. This is different than other watchers that generally have a uv_*_startand uv_*_stoppair 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_*_startuv_*_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 线程、定时器)。在这种情况下,我们可以只使用几个标准来比较这些库:

  1. 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.
  2. 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.

  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和几个视频谈话,所以很难知道所有的秘密(这个图书馆有很多)。有关函数的更具体讨论,请参阅下面我的评论。

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 .pdfhttp://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 构建脚本可以正常工作。