Skip to content

Instantly share code, notes, and snippets.

Last active April 11, 2024 02:48
Show Gist options
  • Save andreybolonin/2413da76f088e2c5ab04df53f07659ea to your computer and use it in GitHub Desktop.
Save andreybolonin/2413da76f088e2c5ab04df53f07659ea to your computer and use it in GitHub Desktop.

Libuv and libev, two I/O libraries with similar names, recently had the privilege to use both libraries to write something. Now let's talk about my own subjective expression of common and different points.

The topic of high-performance network programming has been discussed. Asynchronous, asynchronous, or asynchronous. Whether it is epoll or kqueue, it is always indispensable to the asynchronous topic.

Libuv is asynchronous, and libev is synchronous multiplexing IO multiplexing.

Libev is a simple encapsulation of system I/O reuse. Basically, it solves the problem of different APIs between epoll and kqueuq. Ensure that programs written using livev's API can run on most *nix platforms. However, the disadvantages of libev are also obvious. Because it basically just encapsulates the Event Library, it is inconvenient to use. For example, accept(3) requires manual setnonblocking after connection. EAGAIN, EWOULDBLOCK, and EINTER need to be detected when reading from a socket. This is also the root reason why most people think that asynchronous programs are difficult to write.

Libuv is even more high-level. Libuv is a set of I/O libraries that joyent makes to Node. This also led to the biggest feature of libuv is the callback everywhere. Basically, libuv uses callback processing wherever possible blocking. This actually reduces the programmer's workload. Because when the callback is called, libuv guarantees that you have something to do, so handles like EAGAIN and EWOULDBLOCK are not programmers' jobs, and libuv will silently help you out.

Libev only tells you when a socket reads or writes, “XX socket can read/write, and figure it out.” Often we need to apply for memory and call read(3) or write(3) to respond to I/O events.

Libuv is slightly more complicated. We describe reading/writing two parts.

When the interface is readable, libuv will call your allocate callback to apply for memory and write what it reads. When reading is complete, libuv will call the callback function you set for this socket, with the buffer information in the parameters. You only need to deal with this buffer and free it off. Because data is read from the buffer, the data is already ready when your callback is called, so programmers don't have to worry about blocking.

The handling of writing is more clever. Libuv does not have a write callback. If you want to write something, just generate a write request and throw it to libuv along with the buffer you want to write. libuv will add your write request to the write queue of the corresponding socket and press it when I/O is writable. Write in sequence.

C has no closures, so determining the read-write context is a problem that libuv users need to face. Otherwise, the program will not be able to tell which data it is. In this regard, libuv, like libev, uses a void *data to solve the problem. You can use the data member to store anything, so when the buffer comes, simply cast the data to the type you need is OK.

Libev does not have asynchronous DNS resolution and this has been a widespread problem.

Libuv has asynchronous DNS resolution, and the result of the parsing is also notified through a callback.

Libev is completely single-threaded.

Libuv requires multi-thread library support because it internally maintains a thread pool to handle asynchronous calls such as getaddrinfo(3).

Libev seems to be the author's own development, version management is still using CVS, the community participation is obviously not high.

The libuv community is very active. People raise the issue and contribute code almost every day.

Libev does not support IOCP, if you need to run the program under Win will be very troublesome.

Libuv supports IOCP and there is a corresponding script to compile the library under Win.

Q: Did bloggers have their benchmarks before and how did their previous performance compare?

A: At the time, I wrote a simple HTTP Hello World Server with libev and libuv. The specific results are not clear, but it can be said that the performance gap is within 5%.

Q: Does libuv use libev as the implementation of non-blocking IO on Unix? Will the number of threads in the thread pool in libuv increase? If the upper limit is reached, will the block appear?

A: 1. libuv did not use libev at all 5 months ago. See; 2. libuv's thread pool is fixed at 4 in BSS. See: ; 3. The libuv thread pool shares a work queue, so the block will not appear

Libevent : The most famous and widely used, long-established cross-platform event library; libev : Compared to libevent, the design is more concise and the performance is better, but it is not good enough for Windows support; libuv : The development of node requires a cross-platform process The event library, they preferred libev, but also to support Windows, so re-packaged a set of * libev under *nix, Windows using IOCP to achieve;


Copy link

Nice write-up, thanks for sharing (found it via a Google search).

Copy link

Спасибо, Андрей!

Copy link

vsyrovat commented Aug 7, 2021

Отлично, спасибо

Copy link

lambdaX commented Jan 30, 2022

many thanks to @andreybolonin @robbie-cao

Copy link

Good ! it`s usefull !

Copy link

drok commented Jul 31, 2022

Thank you for this to-the-point summary. I used libuv many years ago but forgot why I chose it; I'm starting a project with a lot of I/O and performance expectations; Your summary refreshed my memory perfectly.

Copy link

laoshaw commented Jul 3, 2023

what about libevent? or even io_uring?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment