C++20’s Coroutines for Beginners - Andreas Fertig - CppCon 2022

แชร์
ฝัง
  • เผยแพร่เมื่อ 26 ส.ค. 2024
  • cppcon.org/
    ---
    C++20’s Coroutines for Beginners - Andreas Fertig - CppCon 2022
    github.com/Cpp...
    You've heard about this new feature in C++20, coroutines, but it's the first time you have encountered this term? Then this talk is what you're looking for. We start from the beginning with just "normal" functions. Next, we introduce coroutines.
    Using them, we explore the various customization points C++ offers. We look at what the new keywords co_await, co_yield, and co_return are for.
    Sadly, we also have to talk about how to write a generator for a coroutine since there is no STL part for that in C++20.
    Another distinction we make is between cooperative and preemptive multitasking, opening the door for another beauty of coroutines, why we don't need locks.
    By the end of this talk, you've learned what coroutines are and where you can use them.
    ---
    Andreas Fertig
    Andreas Fertig, CEO of Unique Code GmbH, is an experienced trainer and lecturer for C++ for standards 11 to 20.
    Andreas is involved in the C++ standardization committee, in which the new standards are developed. At international conferences, he presents how code can be written better. He publishes specialist articles, e.g., for iX magazine, and has published several textbooks on C++.
    With C++ Insights (cppinsights.io), Andreas has created an internationally recognized tool that enables users to look behind the scenes of C++ and thus to understand constructs even better.
    Before working as a trainer and consultant, he worked for Philips Medizin Systeme GmbH for ten years as a C++ software developer and architect focusing on embedded systems.
    You can find Andreas online at
    andreasfertig.com
    __
    Videos Streamed, Edited, and TH-cam Channel Managed by Digital Medium: online.digital-...
    #cppcon #programming #coding

ความคิดเห็น • 63

  • @Fetrovsky
    @Fetrovsky ปีที่แล้ว +15

    I like how he finished with "I am Fertig." I also appreciate the explanation for us non-German-speakers.

  • @tomaszdudek3469
    @tomaszdudek3469 ปีที่แล้ว +27

    In my opinion this is the best presentation about coroutines with a few basic example that covers different ways of passing/getting values from coroutine. Thank you Andreas

  • @beaujamo
    @beaujamo ปีที่แล้ว +26

    The amount of existing knowledge about C++ and concepts like multi threading, async io, future and promise needed to just understand the behind the scenes of a co-routine is enormous. Good luck with collaboration with beginners and developers with different backgrounds with this. The learning curve is really steep and is a recipe for a debugging nightmare if everyone don't fully understand all the concepts!

    • @llothar68
      @llothar68 ปีที่แล้ว +2

      To understand coroutines you don't need any multithreading or async. Don't know where this idea is coming from. They are just functions. So you need understand function frames the stack/automatic variables and lambdas. It's just very bad taught so far. They are a state machine and you have to give some code points to the compiler.

    • @1InVader1
      @1InVader1 ปีที่แล้ว +3

      It's really not that complex. It's literally just a function which you can suspend and jump out of and then jump back in and continue where you left off.

    • @DavidRomigJr
      @DavidRomigJr 8 หลายเดือนก่อน +4

      After having to tweak a coroutine once for work, I’ve watched a bunch of videos to try to understand the concepts and how they work. Most videos have been confusing. Some I kind of get. One explained it in a way that made it easy to understand, talking about things like the way the compiler sees things and what-not, with the audience asking great questions, and it really was simple. I think the problem with a lot of videos is they start with use cases (sometimes good ones) without explaining what coroutines are first.
      It’s as simple as Invader said, as a tool, a coroutine is a function that can suspend and resume itself, can be resumed, and can optionally return data. That’s it at its core. Part of what I think makes it off-putting is I’m not used to functions being able to exit mid-function and then resume later. It stores its local data in a frame, that in C++ is usually stored on the heap (making it “stackless”). The compiler adds control code to the function that, for me, knowing made it easier to understand.
      What makes it important are its use cases. There 2 I keep seeing come up. As a generator where you repeatedly call it to generate the next piece of data, such as in a sequence. And, when paired with a good multi-threaded scheduler, as a task that lets you write a chain of asynchronous calls in the way you would normally write blocking synchronous ones, making it easier to read, but without actually blocking (because of the suspend and resume functionality).
      Since coroutines themselves are really flexible, I’m sure there’s other use cases. I’m still watching videos to learn more, and I still find many confusing even after learning the basics. I think a lot of it is using them requires thinking differently and they presume you know things you don’t or try to explain them in the context of confusing use examples. Many presume a multi-threaded scheduler but don’t explain it because libraries like Boost come with one, but while useful with coroutines, are not apart of coroutines themselves.
      That’s been my experience so far. I’m not sure how clear I was as I’m still a novice with coroutines, but hopefully it’s helpful to someone. I’m going to go watch my next video to see if I can learn more.

  • @dagoberttrump9290
    @dagoberttrump9290 ปีที่แล้ว +15

    nobody: How complicated do you want it to be?
    committee: yes

  • @jakubskop73
    @jakubskop73 ปีที่แล้ว +12

    Very useful for a beginners like me. These new features being added always take some time to get your head around

  • @joakimhove
    @joakimhove ปีที่แล้ว +6

    This was with a wide margin the best presentation I have seen on the topic. Thank you

    • @CppCon
      @CppCon  ปีที่แล้ว +2

      Very pleased to hear that the presentation was helpful.

    • @andreas_fertig
      @andreas_fertig ปีที่แล้ว +4

      Thank you! That means a lot to me!

    • @garyp.7501
      @garyp.7501 7 หลายเดือนก่อน +1

      I agree. Being new to C++ Coroutines I found this very helpful.

  • @christer8964
    @christer8964 ปีที่แล้ว +5

    Funny!
    Was just reading chapter two from your book and took a break and this video popped up.

    • @andreas_fertig
      @andreas_fertig ปีที่แล้ว

      I hope you enjoyed both. This talk uses a different approach and different examples compared to the one in my C++20 book.

  • @Roibarkan
    @Roibarkan ปีที่แล้ว +7

    9:50 Technically both co_yield and co_await can be used for input and output. In fact co_yield can be considered as a co_await for the coroutine’s promise object (‘co_yield x’ is like ‘co_await promise.yield_value(x)’)

  • @serhiymalokhatko
    @serhiymalokhatko ปีที่แล้ว +1

    The best ever explanation of what the beast it is!

    • @andreas_fertig
      @andreas_fertig ปีที่แล้ว

      I'm glad I could shed some light on coroutines!

  • @HamzaHajeir
    @HamzaHajeir 9 วันที่ผ่านมา

    Well elaborated.

  • @Fetrovsky
    @Fetrovsky ปีที่แล้ว +2

    Andreas puts the Fun in Function.

  •  ปีที่แล้ว +3

    Thank you Andreas. A very nice presentation!

    • @andreas_fertig
      @andreas_fertig ปีที่แล้ว

      Thank you! I'm very pleased to hear that you liked my presentation.

  • @dreamdrunk539
    @dreamdrunk539 ปีที่แล้ว +1

    This is an amazing introduction. Thank you all who participated in this!

    • @andreas_fertig
      @andreas_fertig ปีที่แล้ว

      I'm glad you enjoyed my presentation!

  • @s1lentssh
    @s1lentssh ปีที่แล้ว +1

    Thank you for this lecture, very informative

  • @Roibarkan
    @Roibarkan ปีที่แล้ว +2

    11:55 technically, the compiler deduces the promise type as ‘std::coroutine_traits::promise_type’ which defaults to ‘wrapper_type::promise_type’

  • @origamibulldoser1618
    @origamibulldoser1618 ปีที่แล้ว +1

    Has the lambda foot gun been addressed yet?

  • @chololennon
    @chololennon ปีที่แล้ว +13

    Why in C++ things are always more complex than in other languages? Why not have a ready to use solution without coding like in Node.js, Python or even Rust? IMHO the language (or the committee?) has lost its way long time ago.

    • @hendristeenberg8749
      @hendristeenberg8749 ปีที่แล้ว +6

      This is just the framework around which the ready solution wilk be built (it is comming in c++ 23 as far as I know). The availability of the underlying framework allows some really crazy shit such as sharing a single thread between multiple coroutines or batching yielded results before actually suspending.

    • @NoNameAtAll2
      @NoNameAtAll2 ปีที่แล้ว +3

      python's coroutines create their own stack, so are huge and clunky when speed is required
      like, f(i for i in range()) can be a lot slower than f([i for i in range()]) just because of all generator's use (and that's without comparing creation costs)
      c++ coroutines are bone structure for multiple high speed applications
      and normal users will get their std::generator in ++23

    • @dreamdrunk539
      @dreamdrunk539 ปีที่แล้ว +1

      For historical reasons probably. C++ is a really old language and keeping it modern is really hard.

    • @MrDarkoiV
      @MrDarkoiV ปีที่แล้ว

      You get convience by sacrificng performance in some cases, for most programmers its enough. But C++ is for those who might need performance in those cases, and thats why it looks how it looks.

  • @coding_with_thomas
    @coding_with_thomas ปีที่แล้ว

    Great and helpful video 👍👍

  • @CaptG4321
    @CaptG4321 ปีที่แล้ว +1

    Is the code available for download?

  • @OREYG
    @OREYG ปีที่แล้ว

    Isn't there a problem with this 'Scheduler'?
    Lets imagine you have 3 functions:
    a() -> co_await b;
    b() -> co_await c;
    c() -> while(true) co_yield;
    we run a(); and what happens is that coroutines for [c, b, a] are pushed into the scheduler's list in that order, then we yield in c once more; And now our order becomes [b, a, c], and it would erroneously continue with b ahead of time.

  • @axe863
    @axe863 10 หลายเดือนก่อน

    I would assume the best application for this is for hybrid CPU + accelerators ???

  • @guillermotomasini
    @guillermotomasini ปีที่แล้ว

    good stuff for a technical interview :-( I hope to find some library wrapper in order to simplify this mess, thanks.

  • @laizili
    @laizili ปีที่แล้ว

    It's a great talk about coroutine. where can i find the keynote in the talk ?

  • @User-cv4ee
    @User-cv4ee ปีที่แล้ว

    Are the slides uploaded for this talk? There is so much to keep track of at the same time.

  • @dekadebashish
    @dekadebashish ปีที่แล้ว

    Great talk! Can we get the presentation PDF ?

  • @TheMR-777
    @TheMR-777 ปีที่แล้ว +7

    It's *SUPER POWERFUL* now I get it.
    Thanks a lot Mr. Fertig for this informative talk, and
    a huge thanks to CppCon for being a great platform for these wonderful knowledge :)

    • @CppCon
      @CppCon  ปีที่แล้ว +1

      Your comments are much appreciated, thank you.

    • @andreas_fertig
      @andreas_fertig ปีที่แล้ว +1

      Great! I'm glad that I could show the powers of coroutines.

  • @mytech6779
    @mytech6779 9 หลายเดือนก่อน

    Now I want to know how the compiler interperets coroutines as machine code, and therefore how they interact with CPU cache and pipelining(branch prediction).
    I am assuming the primary benefit of coroutines is essentially to combine the tasks of two threads into a single thread. This way a generator would create the generated object directly in a core register ready for the caller to use; as opposed to passing an object, writing the output to memory so another thread can load it from mem (Even as a cache hit the write-load of a shared objrct will require several cycles plus a few more cycles for locks or atomics to sync.)
    As such, will the coroutine instructions and caller instructions be in direct contention for the limited L1i? I mean will the caller and a large coro constantly be displacing each other as big chunks whenever the coro is called and suspended, or will the overall thread be unrolled and caller interleaved with the coro leading to a fairly linear set of instructions from a machine perspective (and thus simpler cache behavior)?

    • @garyp.7501
      @garyp.7501 7 หลายเดือนก่อน

      "primary benefit of coroutines is essentially to combine the tasks of two threads into a single thread. "
      Well, my use case was to use coroutines to buffer reads from the Web and writes to a database. Where the cooroutine would make the request and yield to the thread while awaiting the results of the http request, or the write to the DB. (I did this in GoLang where there is less customization, in fact almost none, and what seems like less boilerplate.). The general theory is that you use a cooroutine where the cost of the call is significant, ie the program could do useful work while awaiting the result. The way GoLang recommends communication with the coroutine is through a "channel" which is essentially a vector with a mutex on it.

  • @NoNameAtAll2
    @NoNameAtAll2 ปีที่แล้ว

    I feel like more slides were needed
    not even for more info, but to pull atrention to specific parts of the code as presentation goes along

  • @yizhang7027
    @yizhang7027 10 หลายเดือนก่อน

    Please make short videos for beginners.

  • @richardmarcoux750
    @richardmarcoux750 10 หลายเดือนก่อน

    Is this pseudo code? Are there really "not" and "or" keywords added to the language?

  • @pabloariasal
    @pabloariasal ปีที่แล้ว

    Very nice talk! I'm curious as to how the coroutine lifetime is handled in the scheduler example, as no one is calling handle.destroy() explicitly. Is this a leak or do we hav some sort of built-in lifetiem management?

    • @Roibarkan
      @Roibarkan ปีที่แล้ว

      I believe that the fact that final_suspend() returns std::suspend_never (slide 27) indicates to the compiler to destroy the frame (and destruct the promise) when the coroutine ends

    • @dagoberttrump9290
      @dagoberttrump9290 ปีที่แล้ว

      No it will leak if you don't provide promise_type::return_void(). That's why you wrap your coroutine handle and provide all the fancy destructor / std::exchange stuff.

  • @hiftu
    @hiftu ปีที่แล้ว

    I think it is a design issue if we need a talk titled for beginners.

  • @Roibarkan
    @Roibarkan ปีที่แล้ว +1

    23:30 I think performing#include inside a struct is quite unorthodox

    • @dreamdrunk539
      @dreamdrunk539 ปีที่แล้ว +2

      Not if it's just a presentation

  • @alexmarkov9918
    @alexmarkov9918 ปีที่แล้ว +1

    Code is unreadable. At least on Chrome/ios

  • @colinkennedy
    @colinkennedy ปีที่แล้ว +7

    Disappointed by how verbose and "loaded" this new C++ co-routine feature is. It's a far cry from how easily you can define these same concepts in Rust or Python.
    I could see co-routines being used by API authors of a very core library but the majority of people are better off writing a class with some state, than they are spending time trying to grok this mess.

    • @NoNameAtAll2
      @NoNameAtAll2 ปีที่แล้ว +3

      this isn't python's generators
      that would be ++23's std::generator
      these coroutines are bone structure for many more, much faster constructions

    • @Obey644
      @Obey644 ปีที่แล้ว

      Could you point me to the rust coroutines? Last time I was looking there were none.

  • @Dziaji
    @Dziaji ปีที่แล้ว +22

    This feature is complete cryptic garbage. I really hope no one ever uses this nonsense. It would be way easier to write a class that holds state and has functions that you call to get values out.

    • @JohnB5290
      @JohnB5290 ปีที่แล้ว +4

      What you are used to is always easier than something you have to learn first. That's why "easy" often is not a quality criterion, in neither direction. After having written the wrapper type ("Chat"), writing different coroutines is much easier than writing different classes for implementing different behaviours.

    • @Voy2378
      @Voy2378 ปีที่แล้ว +2

      while I agree I hope you first read some boost asio code so you will see things can be much much worse...

    • @axilmar254
      @axilmar254 ปีที่แล้ว +1

      What the committee has done is to provide:
      a) a transformation of the code that uses co_await, co_yield and co_return.
      b) a way to save and restore the CPU context.
      That's all they did.
      The actual implementations are left to the user of the language, i.e. the provider of libraries.
      Eventually the language will provide simple coroutine objects, but first they need to provide the low level API.
      You can certainly do without coroutines...if I need to program my own object that generates numbers or iterates a vector or two vectors, why not simply write an object that does the job and holds the appropriate state?
      But then there is stuff like the scheduler and tasks which are not doable with simple objects, because c++ does not provide an official way to save and restore contexts (there is stuff from C, like getjmp/setjmp, but that has a lot of limitations). C++ co-routines can do this kind of task scheduling though, because they keep the appropriate contexts and allow suspension and resumption of those contexts.

  • @mothafucka
    @mothafucka 6 หลายเดือนก่อน +1

    Even though everybody tries to push the "it's better than callbacks" theory, this is unbelievably complex and bad. And no, it's not better than callbacks. We didn't have to spend a month figuring out what callback is. If the same functionality could not have been achieved in a better way, then this should have been dropped from the very beginning.