这是用户在 2024-7-10 18:35 为 https://blog.logrocket.com/a-practical-guide-to-async-in-rust/ 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?
2020-06-25
2974
#rust
 卡尔·弗雷德里克·萨姆森
20761

2020 年 6 月 25 日 ⋅ 10 分钟阅读


异步实用Rust指南


卡尔·弗雷德里克·萨姆森

位于挪威的程序员,对并发系统感兴趣。我很好奇事物是如何运作的,无论是计算机还是其他感兴趣的领域。

Recent posts:

Working With The Angular Tree: Flat Vs Nested Trees And More

Working with the Angular tree: Flat vs. nested trees and more

The Angular tree view can be hard to get right, but once you understand it, it can be quite a powerful visual representation.

Lewis Cianci
Jul 9, 2024 ⋅ 20 min read
The Top Headless Ecommerce Solutions For Frontend Dev

The top headless ecommerce solutions for frontend dev

Explore the top headless commerce platforms tailored for frontend ecommerce development, with free and paid options like Saleor and Shopify.

Fimber Elemuwa
Jul 9, 2024 ⋅ 6 min read
Exploring Native File Watching In Node Js Version 22

Exploring native file watching in Node.js v22

Native file watching being stable in Node.js 22 raises a question: is it a worthy candidate to replace the industry favorite Nodemon?

Oghenetega Denedo
Jul 8, 2024 ⋅ 7 min read
Headless UI Alternatives: Radix Primitives, React Aria, Ark UI

Headless UI alternatives: Radix Primitives, React Aria, Ark UI

Check out alternatives to the Headless UI library to find unstyled components to optimize your website’s performance without compromising your design.

Amazing Enyichi Agu
Jul 5, 2024 ⋅ 8 min read
View all posts

23 Replies to "A practical guide to async in Rust"

  1. 3. Spawning blocking or CPU-intensive tasks
    uses `use tokio::runtime::task;` which causes an error. The example before that uses `use tokio::task;`.
    Is the former a mistake?

    1. Starting the runtime
    with `#[tokio::main]` is there implicitly `app()` called?
    This doesn’t seem to work for me.

  2. You’re right. It should be `use tokio::task;` as in the earlier example. I’ll check if I can get that corrected. Thanks for catching.

    with `#[tokio::main]` is there implicitly `app()` called?

    No, in the first example `app` becomes your “asynchronous main”, in the second example the macro turns you “main” into your “asynchronous main”. What happens behind the scenes is pretty much the same though but you lose access to your “synchronous main” in the latter example.

  3. Looks like the “shorter version” should be
    “`
    #[tokio::main]
    async fn main() {
    app().await;
    }
    “`

  4. I had to change
    “`
    let res = future::ok(“Hello world”.to_string()).await?;
    “`
    to
    “`
    let res = future::ok::<String,Box>(“Hello world”.to_string()).await.unwrap();
    “`
    to get rid of compile errors

  5. “CPU-intensive tasks”
    `let res= task::spawn_blocking(move ||analyze(txt)).await?;`
    is missing a `&`
    `let res= task::spawn_blocking(move ||analyze(&txt)).await?;`

  6. I guess the issues were meant as an exercise for the reader 😉
    Thanks for posting. Very helpful.

  7. You could write that but if you `cargo expand` (cargo install cargo-expand) the example I wrote you get something like this:
    “`
    fn main() {
    tokio::runtime::Builder::new()
    .basic_scheduler()
    .threaded_scheduler()
    .enable_all()
    .build()
    .unwrap()
    .block_on(async {
    {
    {
    todo!();
    }
    }
    })
    }
    “`

    As you see the “app” part is wrapped in an async block and passed to the runtime so “main” would in essence function like the “app” in the example above.

  8. Yeah, you’re right. I was trying to avoid these in this article but it seems I inadvertently introduced it in those examples. I think it’s better to change it to:

    “‘
    async fn our_async_program() -> Result {
    future::ok(“Hello world”.to_string()).await
    }
    “‘
    Since the compiler can infer the rest in this case. Thanks for pointing it out.

  9. Yes, you’re right. analyze took a “String” in an earlier draft but I changed that without catching this one. Should be fixed soon.

  10. Glad you enjoyed it. Well, I couldn’t make it too easy 🙂 Seriously, thanks for posting. The next person testing all the code should have a slightly easier time, though.

  11. Hi Philip. I see where the confusion lies now. You see, `#[tokio::main]`is a macro that rewrites `fn main()` in a way that the code ends up looking like the first example.

    The difference is that the code you write in a main function with `#[tokio::main]` is wrapped in an async block instead of put in a function called `app` but the end result is pretty similar.

    I posted the output from the macro in another answer below but it doesn’t look pretty in the comments section here. If you want to check it out for yourself install `cargo install cargo-expand` and run `cargo expand` in the root of a project with the example code in `main.rs`. You’ll see what it expands into.

  12. > // Returning errors using `?` in iterators can be a bit difficult. Using a
    // simple for loop to inspect and work with our results can often be more
    // ergonomic

    What’s wrong with `try_for_each`?

  13. Hi Daniel.

    That’s a good suggestion, but I feel the example gets harder to understand using Iterators since we can’t simply unwrap using `?` as we do in the rest of the examples.

    `results` is of type: `Vec<Result<Result<(u64, u64), Box, JoinError>>` which is a nested result making the iterator version pretty difficult to understand for people not intimately familiar with functional style programming.

    We might as well use `try_fold` instead of `try_for_each` if we were to do this operation using a functional style so the code would look something like this:

    “`
    let (total_ones, total_zeros) =
    results
    .into_iter()
    .flatten()
    .try_fold((0, 0), |(total_ones, total_zeros), res| {
    res.map(|(ones, zeros)| (total_ones + ones, total_zeros + zeros))
    })?;
    “`

    I feel it makes things more complicated than it needs to be in an example where the main focus is on keeping the code easy to read for a wide audience without really giving a lot of benefit in return 🙂

  14. Thank you soo much Carl for this amazing article, it has helped me a lot to polish my understanding of async Rust.

  15. The slowwly service seems broken or more “sloww” than intended, so the examples do not really work right now.
    You can work around that by requesting e.g. `http://example.com` and sleeping in the appropriate place using `tokio::time::sleep(Duration::from_secs(1)).await;`. Otherwise good introduction!

Leave a Reply