Crust of Rust: async/await

Поделиться
HTML-код
  • Опубликовано: 19 ноя 2024
  • НаукаНаука

Комментарии • 182

  • @yankee-in-london
    @yankee-in-london 3 года назад +180

    I often feel I don't have enough time to watch a 30 minute video but spending 2+ hours watching your content is something I will make time for. Fantastic contribution to grokking Rust ... thank you.

  • @dinckelman
    @dinckelman 2 года назад +12

    I'm not even a Rust engineer, and i've still sat through most of the video. This is the kind of content I love watching.

  • @echosystemd
    @echosystemd 3 года назад +88

    Wow, this introduction is spectacular. Thanks for the beautiful content.

  • @maxwellborden
    @maxwellborden 3 года назад +31

    This was great! Even though you described it before, I didn't _get_ the "await/yield returns back to the thing that awaited" part until you answered the "do futures stay on a thread" question and then it clicked. And the async trait fn part was great because it always seems more intuitive when you describe why things that I expect should work, don't work. It also tied off why the stack variables part was important so nicely.

  • @nimaimpatel
    @nimaimpatel Год назад +3

    I finally understand the formal difference between concurrency and parallelism because of the 01:19:00
    Your content is amazing. Thank you for putting it out!

  • @stepan_romankov
    @stepan_romankov 9 месяцев назад +3

    Thank you so much. I feel I finally getting into rust and start understanding why compiler complains on my code and how to fix it.

  • @Adam-cn5ib
    @Adam-cn5ib 3 года назад +7

    This channel is the only one of its kind. Please don't ever stop! :)

  • @WilliamBrumble
    @WilliamBrumble 2 года назад +2

    Man, was really hard wrapping my head around this, until I found this video.
    Thanks for sharing.

  • @vitorsantos6310
    @vitorsantos6310 2 года назад +5

    For me the easiest way to understand async was writing it in C.
    Of course that not everyone knows C syntax, but it really gives you a complete understanding of how simple async is and how you can leverage blocking syscalls

    • @cashpay50
      @cashpay50 Год назад +3

      are there any resources out there about this? I kinda want a guide to implement this, thanks in advance!

  • @PiyushKumbhare10
    @PiyushKumbhare10 3 месяца назад

    Pretty new to Rust and don't really have any async/await requirements or anything, but I've always wondered how it worked under the hood. This was the perfect video for learning, thanks so much 😄

  • @deformercr6680
    @deformercr6680 8 месяцев назад

    This was an amazing watch! The state machine unveil was an "aha" lightbulb moment for me, since I knew some of the background of how async executors work, but didn't really know how the macros worked and how the desugaring happened.
    Also, now that async traits are a thing, and RPIT in traits work, it would be great to have a follow up video discussing the new way and what are the gotchas there.
    Thank you so much for putting out amazing educational material like this for free! I only started learning rust like a week ago and I feel like I understand stuff so much more than I would expect to because of deep videos like this!

    • @jonhoo
      @jonhoo  8 месяцев назад +1

      You may find ruclips.net/video/CWiz_RtA1Hw/видео.htmlsi=GcR0lZnT3tKds9UO interesting too :)

    • @deformercr6680
      @deformercr6680 8 месяцев назад

      @@jonhoo wow, thank you so much!

  • @pedro.guedes
    @pedro.guedes Год назад +1

    thanks... it's great when we can see through the magic and the world makes sense again! I watch these things for start to finish...

  • @wesleychaffin4029
    @wesleychaffin4029 Год назад

    Manually writing async FSMs in C really gives you appreciation for the niceties of this syntax sugar

  • @Tszyu01
    @Tszyu01 10 месяцев назад

    More of this is needed on RUclips. Thank you for comparing to other languages like JavaScript promises, that helped me personally.

  • @Seacrest.
    @Seacrest. 11 месяцев назад +1

    this is the best lecture about async Rust. Thank you

  • @christopher8641
    @christopher8641 Год назад +4

    You are super good at explaining things! Been learning a lot watching this series. Thanks!

  • @mike2ykme
    @mike2ykme 3 года назад +8

    Hey I’ve always enjoyed your streams but somehow never knew you were writing a book. I’m glad you mentioned it so I was able to preorder a copy!

  • @lemonsh
    @lemonsh 3 года назад +2

    i love you. it helped me SO MUCH! i'm gonna send this video to all my rust friends who struggled with this. awesome channel, i like that livestream idea.

  • @IVIanSour
    @IVIanSour 2 года назад

    I don't know any rust but I still watch these videos, idk why.. you're good

  • @hanskessock3941
    @hanskessock3941 Год назад

    Useful? It was HUGELY valuable, especially given that it's one giant recorded live stream - simply amazing. Cheers!

  • @apffer
    @apffer 8 месяцев назад +1

    excelent explanations on the hows and whys of async. Thank you! 👏🏻👏🏻

  • @douglaslawrie3449
    @douglaslawrie3449 9 месяцев назад

    Thanks for the effort you put into these videos and trying to help people understand difficult stuff. Great teaching, great presentation, great video :)

  • @jonarmani8654
    @jonarmani8654 2 года назад +4

    0:25 "[This] is gonna be one of the shorter streams..." 2.5hrs long? Surprisingly correct.

  • @flwi
    @flwi 8 месяцев назад

    That was very useful. Coming from scala I now have a better understanding and know what the differences are.

  • @cat-.-
    @cat-.- 3 года назад +4

    Lemme try to understand this video through the lens of a JS user, comparing Future with JS Promises:
    *Similarities between js event loop and tokio event loop:*
    - Operates like a state machine
    - Single thread handles unbounded amount of "coroutines", or "callback", or whatever
    - Single threaded = can be stuck dead on a compute-heavy function
    - Single thread = no "real concurrency"
    - Unwraps stack, VM/runtime will save stack somewhere on heap, resumes stack when needed
    - Very good for I/O heavy high "concurrency", quite bad at compute-heavy
    *Differences:*
    - JS promise is just a different way to use callbacks an async fn with multiple breakpoints is just converted into a chain of callbacks, Rust actually inserts instructions to yield halfway in the function's binary.
    - JS promise eagerly executes the executor, but tokio won't execute instructions unless the function is being awaited on.
    - JS Event loop and queuing is in the spec, RS is implemented by some lib like tokio.
    - Tokio give you a way to shoot your own foot (imho) with select!, since it allows for partial completion of an async function. In JS, once you enter an async, there is no way to stop it halfway, it will run its own callback chain without your help and will run to completion barring exceptions. Though this comes at the cost of you not being able to easily discard an async fn in the middle. (You can still have the fn discard itself upon conditions)
    *Questions:*
    - When an interrupt comes but the stack is still occupied by work, JS runtime queues it and waits till stack is clear, then it puts the relevant saved stack back in, IDK how tokio handles this.
    - JS async/await compiles directly into usages of Promises, IDK how rust async/await syntax ties into tokio. Is it yielding?
    - In Rust, if you await on an async fn, and this async fn has multiple breakpoints, do you await it once and it will run to completion, or do you have to await it as many times as it has breakpoints or else it will stuck at the first breakpoint, like in the select! macro?
    Please someone inform me if my understandings so far is correct and if I've missed anything important. Help appreciated!!
    As always, amazing learning material from Jon and I cannot subscribe to your channel more firmly!!!

    • @jonhoo
      @jonhoo  3 года назад +7

      RUclips comments aren't the best for these kinds of long-form questions, but I'll try to give somewhat concise answers. First, tokio is _not_ single-threaded. It can run with a single thread, but by far the most common execution mode is multi-threaded. Also, Rust Futures, unlike JavaScript Promises, have a lot of control over their execution. Specifically, a Rust Future must explicitly say if it can be run in parallel (e.g., with spawn) and concurrently (e.g., with select!/join!). Rust's Futures are also poll-driven, which is a fairly different internal driving mechanism to what NodeJS for example uses under the hood. It's also unclear whether it's right to say that the async stack gets unwound and stored in Rust. In some sense that's true, the effect is the same, but in practice yielding is more about updating the state machine represented by the large (generated) Future type to be in the right state for a future poll.
      For the differences, I'm not sure the first one really applies. In both cases, what gets generated is a sort of "first this, then this" state machine. They may end up with different transformations, but the exact mechanism of that transformation I don't think is too important. You _are_ right that Rust Futures differ from Promises in that they do not implicitly execute though - a Future will never resolve if you just "have" one; it needs to be driven forward by an executor. And yes, in Rust the executor is a library that you explicit opt into, not an implicit global thing. I think you're right that select! is a foot-gun, but it's also a very powerful tool. I do know that there's some work trying to reduce the size of that foot-gun, but.. it's complicated. Especially because we really want to retain the flexibility and power of select!
      For your questions: 1) I'm not sure what you mean by "interrupt", but in Tokio if a task becomes runnable, it does not interrupt a currently running Future (just like in JS) - instead, that Future is placed on the queue of runnable tasks, and will be run at some future point when an executor thread is available to pick it up. 2) all async blocks produce a Future, and tokio works just in terms of Futures (specifically, you pass it a Future and tokio runs it to its eventual completion). 3) Using .await on a value of Future type (like the return value of calling an async fn) means "don't run more code until the output value of this Future is ready" - it does not matter what that Future does internally; it gets to run all the way until it produces its value, at which point the awaiter gets the output value and continues running, much like with a regular function call.
      Hope that helps!

  • @leoxiaoyanqu
    @leoxiaoyanqu 2 года назад

    Just noticed it's your birthday today.. (what are the odds😅) Happy Birthday Jon! Thanks a lot for your high-quality videos! Super helpful!

  • @irlshrek
    @irlshrek 2 года назад +1

    It's funny, coming from JavaScript, conceptualizing futures and async await feels natural. It's threads that confuse me yet it looks like most people in the comment section are in the opposite camp

  • @tiktak7004
    @tiktak7004 3 года назад +1

    Thank you, Jon, I love videos that convey the essence professionally.

  • @simonsellar8482
    @simonsellar8482 3 года назад +2

    Great content and delivery as always! Enjoying the new book too, interesting and challenging!

  • @qm3ster
    @qm3ster 3 года назад +1

    At 1:25:20, one of the `&mut connections` is in the "futures" section and one in the "matched handler block", where all other "futures" have already been dropped, so there wouldn't be any problem with the compiler.

  • @user-ov5nd1fb7s
    @user-ov5nd1fb7s 3 года назад +2

    A good way of picturing it is the number of awaits in your future equal to the number of states in the state machine it's being turned into. 15:00

    • @VivekYadav-ds8oz
      @VivekYadav-ds8oz 3 года назад +3

      Yes that's how it works. Each .await encapsulates a state.
      async fn foo() {
      //State1 begins..
      let x = bar().await;
      //State1 ends ..
      //State2 begins..
      let y = x.prop1.setColor("whatever");
      let z = y.paint_screen().await;
      //State2 ends..
      // State3 begins ..
      return z.status_code;
      //State3 ends..
      //End state begins (shouldn't be poll()ed after this).
      }

  • @amirhossein4684
    @amirhossein4684 2 года назад

    Greate explanation, In Asynchronous mutexes you said that using standard library mutex for short operation is safe but I think it's true for single thread async app, But if we have more than 1 thread always there is a chance that two parts of code refer to same mutex that may lead to deadlock, certainly in short operation this chance is very low but it's still possible.

  • @furkanturkal8414
    @furkanturkal8414 3 года назад +1

    This... is such a great introduction. Thanks for sharing with us.

  • @OlivierEble
    @OlivierEble 3 года назад +1

    This is so awesome. I finally know how to handle the issues that I have met with async in Rust.

  • @diwakargupta0
    @diwakargupta0 Год назад

    I am grateful to find this video. Thanks for awesome explanation :)

  • @detoxifiedplant
    @detoxifiedplant День назад

    excellent content as usual jon 👏

  • @milanrastelli4026
    @milanrastelli4026 3 года назад

    Wow it’s the missing guide on async/wait I’ve been looking for. Watch the full video in one go, every second of it worth it.

  • @furkanaksoy8180
    @furkanaksoy8180 3 года назад

    Man, i wish you run the programs you wrote. Content is great but seeing them in action makes me understand the process better.

    • @jonhoo
      @jonhoo  3 года назад +5

      I'm curious what you feel like that would add in this video? I usually do run my code, but here most of what I've written is more about the types, and running it wouldn't actually print anything 😅 For much of it, there'd also be a bunch of not particularly interesting extra code to write to get things to compile, which would make the video probably twice as long without actual contributing any further insights or understanding.

  • @GamesMaxed
    @GamesMaxed 3 года назад +4

    In the "Stack variables in async" example, how does chunk2 access x?

    • @VivekYadav-ds8oz
      @VivekYadav-ds8oz 3 года назад +2

      Any variable that needs to be shared across states needs to be passed into the new state while transitioning.
      Example,
      // Inside poll() definition
      match *self {
      Self::State1(x) => {
      // Do stuff
      *self = Self::State2(x, some_new_state);
      // That's it for State1's job.
      },
      Self::State2(x, y) => {
      // ...
      *self = Self::End;
      },
      Self::End => {
      panic!("poll () shouldn't be called after future is completed");
      },
      _ => unreachable!(),
      }
      // End of match statement.
      Each time poll () is called, you do work and potentially shift into a different state.

  • @YoloMonstaaa
    @YoloMonstaaa 3 года назад +2

    Thank you, I'm very excited to watch this. :)

  • @andredasilva6807
    @andredasilva6807 2 года назад

    thanks a lot for this stream / vod. its amazing to see into detail, what a feature actually does. i hope we can see some more in the future (pun intended :-))

  • @leetom5192
    @leetom5192 3 года назад

    This is very useful even though I don't use rust, only c++. This will definitely help for when I make my own multithreaded async yield system using c++20 co routine features. (With c++20 modules features, too. Let's see how many compiler bugs I will hit!)

  • @gritcrit4385
    @gritcrit4385 2 года назад +1

    Awesome videos, man. I'm not getting enough free time to learn Rust, nor getting a chance to use it at work. But I hope someday it will happen.

  • @McCourtRC
    @McCourtRC Год назад

    This was incredibly helpful. Thanks!

  • @hermannpaschulke1583
    @hermannpaschulke1583 3 года назад

    Thank you soooo much for this. I Finally understand how this stuff works.

  • @mnn3392
    @mnn3392 2 года назад +1

    Does anyone knows if there is any programming language that supports execution of async with multiple threads like rust?

  • @ezengondolkozom3700
    @ezengondolkozom3700 2 года назад +1

    2:12:23 why does it have to be Arc if it's executing in a single thread? Also why does it have to be a mutex if since it's a single thread then no concurrent access will be happening?

    • @peter9477
      @peter9477 2 года назад +1

      The spawn() call requires it since it is allowed to handle it in a new thread, not only the current one. (It's not necessarily single threaded.)

  • @forouharp9683
    @forouharp9683 3 года назад

    Thank you alot for these streams, this one realy helped me in learning async 👍👍👍🙏🙏🙏❤❤

  • @cthutu
    @cthutu Год назад

    Fantastic talk - the only thing I would say is missing is more detail on how to deal with dynamically sized selects (i.e. the number of futures varies over time). Are Futures(Un)Ordered involved or tokio streams?

  • @matts1839
    @matts1839 Год назад

    Good stuff for hardcore C++ coders other than just dummy hello worlds.. Big up!

  • @mzr4141
    @mzr4141 3 года назад +2

    Would it make sense to have something like off-CPU analysis with bpf for futures on tokio executor? Some async-aware instrumentation might be able to hook into yield points and probe stack traces also saving timestamps.

    • @jonhoo
      @jonhoo  3 года назад +1

      Yup, I think there's been some talk about that already. Possibly by having a tracing subscriber that introduces labels that you can then refer to from bpf too. It's a tooling ecosystem that's very much still in its infancy though!

  • @ZhanhuiLi
    @ZhanhuiLi 2 года назад +1

    So under the hood, rust, go, and other co-routine-like features are still using EPoll on Linux, kqueue on Mac, IOCP on Windows.

  • @matheusbaptistella1880
    @matheusbaptistella1880 9 месяцев назад

    Thanks for the video, really helpful!

  • @jauhararifin10
    @jauhararifin10 Год назад

    If my async function does an IO in a very deep call stack, does it have a lot of overhead everytime the future is polled? Because the poll need to check the state of the top of the call stack, down to the last call stack that actually perform the IO.

  • @thengakola6217
    @thengakola6217 3 года назад +1

    wouldve been epic if u did some basic rust playlist

  • @jRsqILVOY
    @jRsqILVOY 3 года назад +1

    Is there a reason Tokio itself reimplements the std::fs functions directly for example? Rather than having an executor-agnostic async standard library crate?

    • @jonhoo
      @jonhoo  3 года назад +1

      Because in general the I/O resource types (like TcpStream) need to communicate with the executor in order for the executor to know what events to wait for when it decides to put a thread to sleep. And there is no executor-agnostic way to do that currently. We may eventually get something like that, but likely not any time soon.

  • @alvinkuruvilla5163
    @alvinkuruvilla5163 3 года назад +1

    2 streams in 1 day? Christmas came early :)

  • @colin398
    @colin398 Год назад

    With C++ futures, its interesting to note that there is different behavior:
    #include
    #include
    auto f() -> std::future {
    return std::async(std::launch::async, [] {
    std::cout

  • @molozful
    @molozful 2 года назад

    After learning all these details, I have much more respect for Go's goroutine scheduler - effectively everything is made async for you and you can just pretend you have a bajillion threads.

  • @tinnick
    @tinnick 3 года назад

    I clicked like faster than any other video ever. And I usually never do.

  • @d0lvl0
    @d0lvl0 2 года назад

    Is there much support for debugging with async in rust? I'm not able to get break points to trigger in async functions.

  • @bozhidaratanasov7800
    @bozhidaratanasov7800 Год назад

    I know it's a big topic, but I want to dive deeper in how unix based systems actually handle async events and parallel operations. At the very least I want to understand what the basic level async facilities are (network calls, file operations, what else could be async??). Do you have recommendations for materials on this topic?

  • @karelhrkal8753
    @karelhrkal8753 2 года назад

    2:13:00 I feel there needs to be a way to get a warning when calling a blocking function in an async function. It would solve exactly these kinds of problems. I will have to look into it.

  • @protyaybanerjee5051
    @protyaybanerjee5051 3 года назад

    Great channel. Found your reference from the Demikernel paper.
    What is this Vim setup anyway? Looks great

  • @deanroddey2881
    @deanroddey2881 3 года назад +1

    Any reasonable threaded scenario would use a thread pool for handling clients, so it wouldn't be an issue and would (IMO) still be easier to understand. To me the async model feels weird, and hides what is going on more, which I don't consider really a good thing when there are multiple things going on. And it lets you be sure you have a thread per client (if you want that), whereas that's not the case in the async model, where I assume you are depending on some internal heuristics as to how many threads are being created and when. The thread pool based system has a much more controllable response time to connections.
    A generic interface for waiting on things (and for things to make themselves waitable) of course is simple and obvious, and can be used in many ways, without the obfuscation of the async system. And for those things that you really are likely want to want to wait on already probably have OS level (and wrappable by the runtime) mechanisms to have them be done asynchronously and signaled, so you can easily make those waitable without any of the overhead of the async system.
    As a cooperative multi-tasking, it's really not useful for latency sensitive operations, except when everything it does is truly async and very light weight, and if you have to carefully ensure such things, what have you really gained in terms of simplicity? And how easy would it be for code changes to introduce something not light weight without it being at all obvious from reading the code?

    • @cat-.-
      @cat-.- 2 года назад

      If you have a thread pool / green threads, you already are in the woods of cooperative multitasking. All the technical drawbacks of async/await apply, and the choice is simply about taste/style. If you want true OS threads it proves to be too much of an overhead (for example Apache) to be competitive against an async/await high performance server (e.g. Nginx)
      And yes, it is true that async await and coroutines in general is only good if your application is really low on compute, and dead heavy on IO, but that is really what a web server is, for like 99% of the time

    • @deanroddey2881
      @deanroddey2881 2 года назад

      @@cat-.- And there are now many web servers in the world, meaning real ones that need huge I/O throughput, not simple ones in devices and such? They would be about 0.0001% or some such of applications. And could still achieve the same thing even lighter weight than green threads by directly using async I/O.

  • @김태현-o5o6f
    @김태현-o5o6f Год назад

    So, with future and async/await, non blocking IO can be possible with only one thread? Or, is It possible without support of future and async/await ?

  • @zoulock
    @zoulock 3 года назад +1

    Perfect timing!

  • @budiardjo6610
    @budiardjo6610 Год назад

    really love your book, i am learn a lot.

  • @ntippy
    @ntippy Год назад

    5 stars, well done.

  • @jearsh
    @jearsh Год назад

    "rejiggered" ...i'm stealing this

  • @samuraijack7295
    @samuraijack7295 3 года назад

    I didn't get a YT notification for this :(. I would have liked to ask whether it was normal for tokio select! to poll without being explicitly notified by a waker? I have a delay_queue the impls Future and it gets several extra calls to poll by select! before select! actually sleeps and waits for the waker. It feels kinda like debouncing.
    I would expect it the poll function to be called twice. Once on init and then finally when the waker notifies the executor and the future completes...

  • @supersonictumbleweed
    @supersonictumbleweed 3 года назад

    Implementing your own futures is an educational endeavour at this point in time. You'll basically _never_ want to implement Future yourself

  • @cloudsquall88
    @cloudsquall88 2 года назад

    What an amazing video!

  • @arnetriesyoutube
    @arnetriesyoutube Год назад

    This was amazing.

  • @chrisnocker3437
    @chrisnocker3437 3 года назад

    Thanks Jon, learnt a lot!

  • @dimitardimitrov3421
    @dimitardimitrov3421 Год назад

    This is probably a very stupid question, but in foo2() why do you want to “sleep” until a future is resolved? I mean why not just block? What’s the benefit of going to “sleep” and being woken up by the OS if you’re in a non UI environment like a CLI? Is it because you’d save on computational cycles that would normally be wasted? Again, sorry if it’s a stupid question. I understand the use case with select!, but not in a “regular” code.

  • @stretch8390
    @stretch8390 3 месяца назад +1

    Is anyone able to tell me whether anything has changed with async/await in rust since this video? Just wanting to confirm before committing the time

    • @josephsmith5110
      @josephsmith5110 3 месяца назад +2

      async fn in traits is now allowed and RFCs for async closures and naming the return type of (async) methods have been accepted.

  • @ricardopieper11
    @ricardopieper11 3 года назад +2

    The windows IO thing is IO completion ports IIRC

  • @fgtdjkg
    @fgtdjkg Год назад

    brilliant explanations

  • @ketanchaudhari2337
    @ketanchaudhari2337 2 года назад

    If a executor have 2 future spawned and are in epoll ready, one's f.poll() return Ready and done. How will the executor return the ready value to the .await. and will/if it continue after .await on that future?. or will it wait for 2nd future.

  • @thalyssonleite1479
    @thalyssonleite1479 Год назад

    A Masterclass

  • @mback3713
    @mback3713 2 года назад

    I'm interested in your vim configuration -- what extensions are you using & how did you set up your dev environment so nicely!?

  • @gesprengt6561
    @gesprengt6561 2 года назад

    So if you only ever use await and never spawn or join, the program behaves sequentially?

  • @try-h6f
    @try-h6f 9 месяцев назад

    Thanks for the brief

  • @2Jujumba
    @2Jujumba 4 месяца назад +1

    Thanks!

  • @Dygear
    @Dygear 2 года назад

    With the select! macro, lets say I have 2 things that I'm waiting on. The first is a TCP socket that gets data from the network in a highly variable manner. Sometimes I get packets from it between 1 second to 1 hour. (This also means that I have to keep the connection alive by sending it a ping to the server every 30 seconds.) The second is a UDP socket that gets data from the network in a much more consistent manner. I get a packet from there between 50 milliseconds to 6 seconds. Both of these packets are getting parsed out and saved to different SQLite databases on the backend. The TCP one is doing a lot of computation on that packet and indeed could make another TCP connection to another server, or send a HTTP request to another service this takes a lot of time. Is there a guarantee within the runtime that the if I get another TCP packet or UDP packet before that computation is done that it will also handle the next TCP packet as well? Or am I going to spill the next packet on the floor as it flows past what my program is able to handle. What about the UDP side that is waiting for TCP to handle its packet. Given that the TCP side could take several seconds to finish its processing of that packet, would I be dropping UDP packets on the floor because my TCP future is running and hogging the system?

    • @Dygear
      @Dygear 2 года назад

      Partially answered at 55:35 - You would need to call .await on these expensive functions call in the TCP socket to make sure that it yields back to the select call. What it does't answer is if another TCP packet comes in, would that TCP packet get processed as well, or would the new TCP packet clobber the handling of the previous packet that is still in flight, or would it drop that packet, or would it queue the packet for the next iteration into the select macro call. -- The solution (but not the answer) for that comes at 1:27:00 where they talk about giving that packet (or connection in their example) to the executor for them to handle and make progress on until it's done.

  • @omgExodus
    @omgExodus 2 года назад

    Great talk! 👏

  • @nteasushz
    @nteasushz 3 года назад

    Great video. Thanks for sharing.

  • @karelhrkal8753
    @karelhrkal8753 2 года назад

    Never seen the "select" macro, the JS way would be to add .then() on each promise and then do Promise.all(). That way, you can still react to each individual promise resolving but you also have guarantee that the process will not continue until all promises have resolved.
    Not sure how that would work in Rust. Event if you added a .then() function on a future, I guess there might be some complications with the borrow checker. I will have to try it out to find out.

  • @OBLIVIOUSKARI
    @OBLIVIOUSKARI 3 года назад

    What’s the difference between tokio::spawn and spawn_blocking?

  • @petrupetrica9366
    @petrupetrica9366 3 года назад

    I considered rust for writing a highly asynchronous I/O heavy application, however I ran into trouble when I was trying to await on a few lists of futures of different types. Additionally, at the end of a task from a list sometimes I would add some more to one of the other lists, meaning that I had to really select on these lists and depending on which task was finished, possibly modify these lists. I am new to Rust so I don't know if I was missing something but I found no way to do just that (selecting on multiple lists of different types of futures), do you know if / how it could be done?

    • @jonhoo
      @jonhoo  3 года назад +2

      The way I'd do this is to tokio::spawn each future, and then add all the returned join handle futures to a FuturesUnordered which you can then pull from.

    • @petrupetrica9366
      @petrupetrica9366 3 года назад +1

      @@jonhoo Thanks, I used std async just because I thought it's the standard having std in the name :)). But I see tokio is really the most used and fully featured one, I'll try again with tokio and see what results I get.

  • @VivekYadav-ds8oz
    @VivekYadav-ds8oz 3 года назад +1

    I feel really weird that the futures don't really execute until .await is called on them, while there is a background worker thread that could've taken that future and polled it to completion. Are there any executors that immediately start polling the future (in a background thread) as soon as they are made? (Eg: the future in its construction pushes itself to a worker_queue that the executor pops the futures out of and distributes them to worker threads).

    • @VivekYadav-ds8oz
      @VivekYadav-ds8oz 3 года назад +1

      This model of not executing a future immediately only works if you have a lot of futures to poll/execute so that the background thread isn't really wasting time when the future wasn't .await-ed .

    • @jonhoo
      @jonhoo  3 года назад +1

      No, there is no such executor. And there couldn't be - there's nothing special about the creation of a future that an executor could hook into. In fact, even await doesn't actually make a future run. It just says that *when* this future runs, and gets to this point, it must wait for this other future. It's only when a future is given to an executor that it actually runs.

    • @VivekYadav-ds8oz
      @VivekYadav-ds8oz Год назад +1

      ​​@@jonhooWell yes, you are right in that Rust doesn't have some notion of "default constructor" that gets run, which would've made this elegant. However at the expense of more boilerplate, couldn't we write an extension method on Futures, say .run(), that spawns the future in a new Task/parallel compute, and returns some sort of handle that you can call .await on? Would it be possible to do this without too much synchronisation problems?

  • @mibaatwork
    @mibaatwork 3 года назад

    I like this very well. U have a new Abonnement! It is a good idea to use async to build a Gameloop ore should I use threads instead? Or what is the optimal Gameloop for a multi core system?

  • @yushie8158
    @yushie8158 2 года назад +1

    Awesome tutorial!

    • @jonhoo
      @jonhoo  2 года назад

      github.com/jonhoo/configs/blob/master/editor/.config/nvim/init.vim :)

  • @kiffeeify
    @kiffeeify 3 года назад

    @32:52 "every await is an opportunity to chose to do something else". I assume this is only true if the awaited future is not immediately ready (im thinking of `std::future::ready()`) ?! I.e. futures are eagerly progressed, if possible. Only if there are some special os or async-framework specific calls controll will be yielded and other futures may progress. Is that correct?

    • @jonhoo
      @jonhoo  3 года назад +2

      No, futures are *not* eagerly professed. The executor is allowed to to run the same future again, but is under no obligation to do so. And generally it'll take the opportunity to run another future instead.

    • @kiffeeify
      @kiffeeify 3 года назад

      @@jonhoo thanks :)

  • @ivorybanana2183
    @ivorybanana2183 3 года назад

    great intro, mate

  • @LongestYardstick
    @LongestYardstick 2 года назад

    Just bought your book.
    I love the syntax highlighting here, is this a popular vim color scheme?

    • @jonhoo
      @jonhoo  2 года назад +1

      It's called base16-gruvbox-dark-hard

  • @parthikpatel6108
    @parthikpatel6108 3 года назад

    At 57:00, it's mentioned that if there's a future that's blocking on something that takes forever, (and therefore never yields), nothing ever gets the chance to run. But stuff can still run on another thread right? (Assuming the chosen tokio runtime is multithreaded?

    • @jonhoo
      @jonhoo  3 года назад +1

      Yep, I talk about that a little later in the video. The devil is in the details here though. For example, Tokio implements (at least, implemented) an optimization that makes it faster to schedule a future that recently ran, which in turn makes that future not possible to steal. So if you block an executor thread, you _also_ block that additional future. Which may in turn prevent other futures from running that depend on that future running. Basically, blocking the executor can have grave and unexpected consequences, so don't do it 😅

    • @parthikpatel6108
      @parthikpatel6108 3 года назад +1

      @@jonhoo noted. So what I'm gathering so far is that it's fairly easy to reap the full benefits of async/await as long as you adhere to a few simple rules

  • @tanjack9484
    @tanjack9484 2 года назад

    Hello, I saw your video on RUclips above and thought it was very good. I am from China and would like to translate your video into Chinese subtitles for Chinese video sites, what authorization do I need?

    • @jonhoo
      @jonhoo  2 года назад

      Hi there! You don't need any authorization. The videos are licensed under Creative Commons specifically for this purpose. Please provide a link back to the video and/or to my Twitter though :)

  • @parthikpatel6108
    @parthikpatel6108 3 года назад

    In the functional programming world we put our "effectful" operations in an "effect" type (Like cats IO in Scala)... so is it fair to say that in the Rust world, corresponding idea is to use futures and async/await?

    • @jonhoo
      @jonhoo  3 года назад +5

      Ah, no, this isn't a way to describe whether an operation does I/O or not. Synchronous code can also do I/O. It is solely a matter of using a different execution model.

    • @parthikpatel6108
      @parthikpatel6108 3 года назад

      @@jonhoo thanks!!