Coroutine Patterns: Problems and Solutions Using Coroutines in a Modern Codebase - Francesco Zoffoli

Sdílet
Vložit
  • čas přidán 15. 05. 2024
  • cppcon.org/
    ---
    C++ Coroutine Patterns and How to Use Them: Problems and Solutions Using Coroutines in a Modern Codebase - Francesco Zoffoli - CppCon 2023
    github.com/CppCon/CppCon2023
    In over 30 years of experience the C++ community have developed patterns that are effective in writing complex systems. The introduction of C++ coroutines introduced a brand new paradigm, but it changes many of the assumptions of the past. In this talk we'll see common patterns and pitfalls that arise using C++ coroutines, and what solutions are needed to address them.
    Based on the experience working with a heavily coroutinized codebase, this talk will show a collection of common patterns that arise using coroutines. The patterns will cover from code that the compilers today block, to effectively managing resources with RAII, to the need and risks of synchronization. It will present ways to make the code correct, workarounds to obtain the same outcome, or will warn about potential issues that can arise from such patterns.
    The code shown is going to be based on Facebook's Folly implementation of coroutines, but the concepts presented are common across other implementations as well (no previous knowledge of Folly is required).
    This talk is perfect for practitioners that already are trying coroutines in their codebase and want to ensure the code they're writing doesn't contain hidden bugs, but also for people that haven't used coroutines yet and they are evaluating introducing them in their codebase.
    Do you want to discover the new patterns to write correct code with coroutines? Watch this exciting talk!
    ---
    Francesco Zoffoli
    Author of the book “C++ Fundamentals”, passionate about programming languages, maintainable software and distributed systems, he has been using C++ throughout his career and personal projects. Graduated in 2016 with a MSc in Computer Systems Engineering, he joined the industry working for Bloomberg LP.
    Since 2020 he has been building software monitoring systems at Meta.
    He enjoys using C++ to build maintainable systems that work at scale.
    ---
    Videos Filmed & Edited by Bash Films: www.BashFilms.com
    CZcams Channel Managed by Digital Medium Ltd: events.digital-medium.co.uk
    ---
    Registration for CppCon: cppcon.org/registration/
    #cppcon #cppprogramming #cpp
  • Věda a technologie

Komentáře • 22

  • @tianxiasenlin9
    @tianxiasenlin9 Před měsícem +1

    very very good talk

  • @CartoType
    @CartoType Před 3 měsíci +17

    Actual content starts at 3:50.

  • @seheyt
    @seheyt Před 3 měsíci +3

    29:12 The point of enable_shared_from_this is **NOT** that you “just write a deleter that joins scheduled work”, the whole point is that the object stays alive until all scheduled work was completed. So you do not have to deal with any asynchronous operations in its destructor

    • @MakersF
      @MakersF Před 2 měsíci +1

      The question was "how to handle classes which need asynch cleanup and are stored in a shared pointer". The answer is that there isn't a good solution, but in our use cases a class which needs async cleanup is generally a local variable and we can join it in the function. The async cleanup is normally the logic which guarantees that all the work has been joined before destruction.
      If you're designing a system where the class is stored in a shared pointer held only by each unit of work, you could assert in the destructor that all async work is done. But that is not the approach followed by structured concurrency, which instead allows not to have to store state in shared pointers because the unit of work just get references to the class, and the scheduling of work is done in a way that the reference remains alive for the duration of all the work

  • @yokozombie
    @yokozombie Před 2 měsíci +1

    After this talk I am even less confident in a prospect of ever using coroutines in production.

  • @ZahrDalsk
    @ZahrDalsk Před 2 měsíci +1

    Tip: Sponsorblock lets you skip the random AGP men the keep getting put at the start of these videos.

  • @seheyt
    @seheyt Před 3 měsíci

    12:56 is compilation error because Bar has no member f

  • @bobsinclair8990
    @bobsinclair8990 Před 3 měsíci +3

    Anyone knows when module support from C++20 will be implemented in a standard compiler(not msvc)?

    • @arthurozga2722
      @arthurozga2722 Před 3 měsíci

      Not sure about a released version, but if you build llvm from source, you can try it out. Similarly, cmake 3.28 with ninja can be used as a build generator.

    • @RoiEXLab
      @RoiEXLab Před 3 měsíci

      You can already use modules in gcc and clang, however the standard lib hasn't been exposed as a module yet, you can still include it within a module though

    • @bobsinclair8990
      @bobsinclair8990 Před 2 měsíci

      ​ @RoiEXLab ​ @arthurozga2722 Thank you for your replies. I'm talking fully fledged implementation with all bells and whistles i can build a code base on, not playing around without stdlib or some esoteric b2 compiler examples. I've tried since 2017 if I remember correctly and it always breaks for my use cases once I go beyond basics.

  • @JM-hu3xs
    @JM-hu3xs Před 2 měsíci +1

    What baffles me is how complicated it all is.
    Being familiar with JavaScript, I’m very comfortable with its “async/await” keywords, and Promises. The concepts are as old as the ark.
    You can flag any function as async and its return value is implicitly a Promise. You can chain them, and you can simplify a complex sequence of async actions down to something that looks nice and synchronous:
    const user = await getUserById(4);
    await user.setEmail(newEmail);
    const items = await user.getEquippedItems();
    Trivial syntax, and promises that reject are thrown as exceptions when using await.
    It also has generator functions where you just stick an asterisk on the function name and “yield” the value instead of returning it.
    Why is the C++ parallel of this such an unintuitive nightmare?

    • @kuhluhOG
      @kuhluhOG Před 2 měsíci +3

      JS has a garbage collector, C++ doesn't.

    • @CaptainOachkatzl
      @CaptainOachkatzl Před 2 měsíci +2

      because JS is garbage collected. lifetimes of manually managed memory is just a lot harder with async.

  • @passerby4507
    @passerby4507 Před 3 měsíci +1

    I've watched Eric Niebler and many others on coroutines now and I *cannot* for the life of me tell what coroutines are supposed to solve. This talk is titled "problems and solutions", and I thought I'd see examples of problems coroutines solves, but no, it's about problems coroutines *introduces*. If that's not a red flag, you need to get your eyes checked.
    Let me TL;DR coroutines for you: they're over-engineered std::function that uses a whole new set of keywords and nomenclature so that you have no clue what's going on and dangles references left, right and center.
    If someone has a concrete example where coroutines are indispensable, I will gladly be corrected.

    • @fhrflbq70
      @fhrflbq70 Před 2 měsíci +2

      Example: You are writing a server component, which receives requests from users for songs, picks them from database and sends them back to user.
      You can use threads and then wait for user request doing nothing, then send song request to the database and wait for it doing nothing and then send the song. Each thread can handle exactly one user request at a time.
      You can use epoll/uring to fix sync waiting but their interfaces are rather user unfriendly, they are platform dependent and also don't perform all that well when overloaded since they are points of contention.
      Finally you can use coroutines (or stackful fibers): every time you *wait* your execution actually pauses and the executing thread can pick another task. E.g. while you are waiting for user request, thread can handle older requests to database which are finally fulfilled or handle another user requests.
      So in cases 2 and 3 you have multiple requests handled per 1 thread at a time. 2 is worse because it's harder to use and runs worse when scale (millions of requests) is taken into the account

    • @MakersF
      @MakersF Před 2 měsíci +2

      Coroutines are not indispensable in any case since they are syntactic sugar for continuation passing style, which is very common in asynchronous code. But if that isn't something you need, coroutines are not aimed to improve your situation.
      When they are a good fit, it's a nice addition. Which unfortunately, like almost everything in C++, comes with some pitfalls, which this talk aims to uncover and provide possible mitigations for.

    • @MaceUA
      @MaceUA Před 2 měsíci

      no, they're not std::function, theye're std::vector 🤦‍♂️

  • @yaroslavpanych2067
    @yaroslavpanych2067 Před 3 měsíci +2

    Half of issues is because coroutines are executed in different threads. Question: wtf? Why in hell anyone would do it? Coroutine is sugar, therefore, it is completely up to user to guard itself.

    • @anon_y_mousse
      @anon_y_mousse Před 3 měsíci +1

      That's precisely what I'm thinking. It's just a syntactic sugar wrapper around threads anyway. Back some 20-ish years ago I toyed with coroutines in C and none of it was threaded or asynchronous. The whole reason for using them was to avoid threads and locking code while still allowing lazy evaluation, but modern implementations all seem to use threads. Truthfully, I find proper full threads to be easier to use and don't understand why anyone would use or want to use modern coroutines.

    • @MakersF
      @MakersF Před 2 měsíci +8

      Whether the coroutine is executed in multiple threads or not depends on the executor on which it's executed. If for your use case a single threaded model is the correct one, you can use that and not care about synchronization.
      But there are many cases in which you want to make use of multiple threads to parallelize the work, and coroutines support that. The talk calls out some of the things that need to be taken into account in such cases. I hope this helps :)