I am trying to understand asynchronous models in C++. I am investigating 4 libraries that purport to deal with asynchronous I/O:
- liburing (C version, C++ version): provides an interface for io_uring. The C++ version uses coroutines.
- libunifex: implements the C++ sender/receiver async programming model
- Boost.Asio: library for asynchronous network and low-level I/O programming
- CppCoro: provides a large set of general-purpose primitives for making use of coroutines
These libraries have an enormous amount of overlap.
Execution context and io_uring
The future of asynchronous I/O will likely use io_uring on Linux machines. liburing exists to provide an interface for io_uring with io_service. However, libunifex also provides io_uring_context. These both explicitly use io_uring
but have usage similar to Boost.Asio's io_context and CppCoro's io_service.
Can liburing's io_service
, libunifex's io_uring_context
Boost.Asio's io_context
, and CppCoro's io_service
all be used together? If my code included all four of these libraries, would I have 1 execution context from each?
Functionality: opening files
This section contains an example of how CppCoro asynchronously opens a file. I believe this template class would be used in Boost.Asio for asynchronous file access. libunifex has an io_uring_text.cpp doc that includes asynchronous writes to files. Obviously liburing exists for asynchronously writing files.
Should I only use the io_uring specific libraries for file access?
Functionality: networking
Everyone knows that Boost.Asio provides networking functionality. CppCoro does too. The liburing GitHub includes an example echo server that uses low-level C code.
Linbunifex does not appear to include direct networking functionality. I presume it is meant to be combined with some other networking library. Would I combine it with one of the above three libraries to give an old library a sender-receiver interface? How would I do that?
Interface: coroutines
I'm guessing that coroutines are meant to be glue that allows these libraries to exist together. Boost.Asio is compatible with coroutines. liburing4cpp and libunifex have coroutine compatibility as a central feature. CppCoro, on the other hand, is essentially a coroutine library.
Does it at all make sense to talk about using coroutines as glue? Could I say "I will use library A to implement the async function and library B to handle the output of the async function"?
My Questions
Would you expect to see someone use all 4 of these libraries simultaneously? Are any of these libraries meant to be used on top of any of the others?
In cases where functionality overlaps, how do these libraries compare on performance? Is Boost.Asio falling behind new asynchronous models? Is Boost.Asio staying ahead by integrating the most recent asynchronous models? liburing4cpp included a low-level echo server that isn't much comparable to the modern interface of Boost.Asio. How do applications based on low-level io_uring usage compare to applications built using Boost.Asio?
I believe that senders/receivers in libunifex is primarily meant as an interface. Should I use it as an interface to other libraries, for example Boost.Asio?