C++ Coroutines from scratch - Phil Nash - Meeting C++ 2022
ฝัง
- เผยแพร่เมื่อ 25 ส.ค. 2024
- C++ Coroutines from scratch - Phil Nash - Meeting C++ 2022
Slides: slides.meeting...
Survey: survey.meeting...
C++ 20 introduced coroutines into the language. Coroutines have the potential to greatly simplify some types of code - particularly, but not limited to, anything asynchronous in nature. But early adoption has been hindered by both the lack of library support in the standard and the inherent complexity of the feature itself (which, due to that lack of library support, you are typically more exposed to).
Now we have a bit of a “Blind men and an elephant” problem - where we’re getting disjointed glimpses of what coroutines, supposedly, are - without the big picture. I can’t claim to be able to give you a comprehensively big enough picture in a 60 minute talk, but my aim is to plot a journey through it by starting with a motivating example (a typical multiple async task problem), looking at how we might approach this without coroutines, then seeing what coroutines can do for us - and finally looking at what that would look like with library support, too.
Do I understand correctly that the coroutines allow us to return an unfinished result that will appear in the future, but unlike the standard future promise that we have in std::async, we do not hang on the get() method. Thus, the coroutines allow us to make chains of functions where the result of the first function is not yet ready for processing in the second function, while we do not hang on the get() method waiting for the finished result. The same can be done with monadic chain, when we build a pipeline of transformation chains. It's very similar to a car factory. There is a conveyor and there are many machines. Each machine takes the result from the previous one and passes it to the next one. But when there is no input part yet, the machine is NOT IDLE, it begins to do preparatory operations, for example, before installing wheels, it is necessary to take the correct mounting bolts. There is nothing prevents from taking 20 bolts out of the box for fixing the wheels, even if the wheels has not yet arrived from the air pumping machine, which pumps the wheel with air. Thus, the machine for installing wheels will already have time to do something (in other words, it will start its work even the wheel is not ready yet). As soon as the previous machine gives the finished wheels, the machine that installs the wheels on the car will immediately tighten them with ready at hands bolts, since it has already found and taken these bolts during the time while the previous machine was pumping the wheels. Thus, no one is idle waiting for the result from the previous machine.
I have a hard time imagining use cases that would justify the heavy machinery required to use C++ coroutines in their current form. When I first heard of C++ coroutines years ago, I thought I could use them to implement the rules of complex board games, where the state of the game might not be easy to express in a class, for instance because when playing a card, some associated code needs to be executed, which might require every player to make some decision... It's much easier to express those rules as code in a coroutine: Every time players need to make decisions you generate their choices and co_return, the main program tells you what the players chose, and the state of the game is encoded in the stack frame of the coroutine. There might still be some hope for this, but without being able to copy coroutine frames you can't easily use such a game object as part of a search algorithm like alpha-beta or MCTS.