The State of Async Rust: Runtimes - eviltoast
  • d_k_bo@feddit.de
    link
    fedilink
    arrow-up
    13
    ·
    1 year ago

    I think the best part about smol is its composability.

    Unlike tokio which consists of one large integrated library, smol provides many smaller, mostly runtime-agnostic crates e. g. blocking to run blocking I/O on a thread pool or async-lock for async lock primitives.

  • BB_C@programming.dev
    link
    fedilink
    arrow-up
    5
    arrow-down
    1
    ·
    1 year ago

    A good topic to chat about.

    But before that, I should mention that I had to use the browser’s inspector to disable that background color. Light and dark backgrounds are both fine (I have color inversion bindkeyed after all). It’s the ones in the middle like this one that are a no-no.

    And while you could exclusively use the runtime and ignore the rest, it is easier and more common to buy into the entire ecosystem.

    Stats? User surveys?

    I would expect that many users (including myself) actually just use the runtime, directly or indirectly (e.g. via async-global-executor with the tokio feature), while API usage is covered by crates like async-io, async-fs, async-channel, blocking, …etc.

    In fact, I would hypothesize that, from an ecosystem adoption POV, tokio’s only killer feature is hyper’s dependence on it. If it wasn’t for that dependence, tokio’s adoption, I would expect, would be much lower. But this is admittedly anecdotal.

    Any time we reach for an Arc or a Mutex it’s good idea to stop for a moment and think about the future implications of that decision.

    This and the quote above it seem to be Rust intellectuals’ flavor of the month position.

    It kind of reminds me of the lowering dependencies’ compile times craze from a few years ago. Stretching the anti-MT-RT narrative to the point of making bad advice like recommending sync channels for an IO task adds to the parallels.

    The choice to use Arc or Mutex might be indicative of a design that hasn’t fully embraced the ownership and borrowing principles that Rust emphasizes.

    Or maybe you know, using APIs that already existed in std for a reason, as intended!

    It’s worth reconsidering if the shared state is genuinely necessary or if there’s an alternative design that could minimize or eliminate the need for shared mutable state.

    Generally true. But probably false here.

    People reaching for Arc+Mutex/RwLock/… (doesn’t have to be a Mutex) in asyc code are probably aware of alternative designs, but still decide to use Arc+Mutex/RwLock/… when it’s either necessary, or when it actually makes things simpler, and the downsides (performance) are of no measurable relevance, or the alternative design is actually slower (i.e. the multi-threaded runtime is actually helping).

    I would consider arguments that talk about “killing all the joy of actually writing Rust” in this context as either intellectual posturing, or simply disingenuous.


    Otherwise, there is not much to disagree with.

    • anlumo@feddit.de
      link
      fedilink
      arrow-up
      2
      ·
      1 year ago

      As someone who has tried doing multithreaded design with Arc/Mutex, this is a complete nightmare. You constantly get into deadlocks and performance is abysmal, because Mutex is serializing access (so it’s not really async or multithreaded any more).

      • BB_C@programming.dev
        link
        fedilink
        arrow-up
        1
        ·
        1 year ago

        As someone who has tried doing multithreaded design with Arc/Mutex, this is a complete nightmare.

        I myself often use channels. And pass owned data around.

        I don’t think anyone argues that Arc+interior-mutation is ideal. But it’s the over-the-top language like “complete nightmare” that some may take issue with.

        Note that I again make the distinction between Mutex, and all interior mutation primitives. Because Mutex is indeed a bad choice in many cases. and over-usage of it may indeed be a signal that we have a developer who’s not comfortable with Rust’s ownership/borrowing semantics.

        You constantly get into deadlocks and performance is abysmal, because Mutex is serializing access (so it’s not really async or multithreaded any more).

        • Same note about Mutex specifically as above.
        • Avoiding deadlocks can definitely be a challenge, true. But I wouldn’t say it’s often an insurmountable one.
        • What crate did you use for interior mutability, async-lock, tokio, parking_lot, or just std?
    • d_k_bo@feddit.de
      link
      fedilink
      arrow-up
      1
      ·
      1 year ago

      In fact, I would hypothesize that, from an ecosystem adoption POV, tokio’s only killer feature is hyper’s dependence on it.

      AFAICT, the current hyper v1 release candidate only depends on tokio for tokio::sync::{mpsc, oneshot} (and sync is the only enabled feature).

      It’s intended to be runtime-agnostic. See also https://docs.rs/hyper/1.0.0-rc.4/hyper/rt/trait.Executor.html . I agree that its ecosystem is still very tokio-centric.

      • BB_C@programming.dev
        link
        fedilink
        arrow-up
        2
        ·
        1 year ago

        FYI, I had some time to check out hyper v1 today.

        The new API of hyper proper is very low-level. Directly usable API is apparently moved to a hyper-util crate, which, as expected, does have a hard dependency on the tokio runtime.

        So, while it’s good that hyper proper won’t hard-depend on tokio rt, it appears that non-tokio-rt usage will either depend on a higher-level 3d party crate, or a lot of effort from direct hyper dependants to write a lot of glue code themselves.