I was programming node.js in the last days and heavily used the async library. It is a library which introduces functions which handle common workflows in asynchronous programming. There are functions which run asynchronous calls in parallel or after another and call a single callback after all functions are finished (or an error occured).
Are there any librarys like this for C++?
I really like asynchronous programming, but the huge amount of callbacks (all of them with error handling etc) are really hard to read and maintain and are kind of ugly. I would love to continue coding in the way I experienced with the async library.
I guess that such a library is harder to realize in a language with less dynamic typing like C++.
PS: Suggestions how to make async code prettier are also welcome.
edit: I am using g++ with C++11.
edit 2: "Asynchronous" means working with non-blocking functions with callbacks in this context, not running parallel threads in the background. An example is boost:asio.
edit 3: I am already using boost::asio and would like to enhance the readibility of the code (clarity of the control flow, ...) with such a library.
As you must already know, given that you're using it, boost.asio gets you part of the way there. But it's not going to be the same. Let me explain why.
Both node and asio are designed around the idea of a proactor. If you want to do something blocking (or just slow), you submit the job to the proactor, and it runs whenever it's appropriate and then calls your callback when it's finished.
But in node, everything goes through the proactor; there are no other kinds of async APIs. If you want to talk to a MySQL database, the interface takes a SQL statement and calls you back with a rowset. In C++, the interface takes a SQL statement and either blocks before giving you a cursor, or gives you an object that you can poll or block on. For files and sockets, you can ignore all the other APIs like select or aio_read because asio has complete wrappers, but for almost anything else, you have to do the work to write a wrapper, and often it's a lot of work.
More seriously, the standard callback interface in node is callback(error, result), where the result is a JS object, which can have any members that are appropriate. The standard callback interface in asio is void callback(const error_code&), where there is no result. You bind a mutable object into the task. This would already make it more clumsy to do control flow, because there's no way an object can follow another without knowing how its predecessor stashed its mutable data. This also mean that you need shared mutable data (which, unlike node, may be shared across threads), whether you want it or not. But of course the biggest problem is that the data is statically typed. (Often people build C++ classes, and share state by having the tasks be bound methods of the same object, but that isn't actually required.)
Of course you can write code to do fully dynamic objects in C++ (or maybe just one level of dynamicness, like a vector<boost::any> is sufficient), but it's still going to be clumsier to use than in JS, and you'll be giving up much of the performance benefit you were hoping to get by moving to C++.
So, it would be pretty easy to write functions like void async::waterfall(vector<void(const error_code&)>> tasks) that did exactly the same thing as async.waterfall(tasks), but it wouldn't get you all the same benefits you're looking for.
Another point to consider is that you've switched to C++ for a reason: You're on a slow, resource-constrained system. Using a proactor to achieve data parallelism, equivalent to async.forEach, isn't unworkable, but it's not going to be as efficient as a plain old thread pool and a parallel-for library that knows how to use it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With