Live data from Hacker News

Async Rust never left the MVP state

tweedegolf.nl

221–230 of 273 posts

Re: Async Rust never left the MVP state

#221

I recently started working with Rust async. The main issue I am currently facing is code duplication: I have to duplicate every function that I want to support both asynchronous and blocking APIs. This could be great to have a `maybe-async`. I took a look at the available crates to work around this (maybe-async, bisync), but they all have issues or hard limitations.

It'll depend immensely on what you're actually doing, but if it's simple enough you may be able to make a macro that subs out the types & awaits

One of the issue I face is a blocking function that takes a generic constrained by a `trait` and its async version takes a generic constrained by an `async trait`.

Re: Async Rust never left the MVP state

#222
post #193
post #178

Earlier quoted context omitted.

Because foo might call process::abort().

I disagree. If the codegen / optimizer is trying to preserve the rule that futures don’t have side effects until polled, then it seems fine to assume that the future being wrapped also follows that rule. So if I call a foo() that violates the rule, it seems odd to complain that the generated bar() also violates it.

[deleted]

Re: Async Rust never left the MVP state

#224

Async seems like an underbaked idea across the board. Regular code was already async. When you need to wait for an async operation, the thread sleeps until ready and the kernel abstracts it away. But We didn’t like structuring code into logical threads, so we added callback systems for events. Then realized callbacks are very hard to reason about and that sequential control is better. So threads was the right program…

You don’t have threads on embedded, but you want a way to express concurrent waiting. Different problems altogether

You can, though. We used pthreads (well, pthresd compatible API) in production at massive scale on the ESP32-S3.

Re: Async Rust never left the MVP state

#227

Earlier quoted context omitted.

Threads are a scheduling model that delegates to the OS scheduler. Async style provides a primitive for creating a custom scheduler but is not a scheduler per se. To use a custom scheduler you must first disable the existing schedulers your code is using by default for both execution and I/O. That means no OS scheduling. Thread-per-core architectures with static allocation and direct userspace I/O is the idiomatic wa…

That’s not what I asked.

I'm going to hop in and say this would be a good exercise for you, instead. The industry has, in general, decided upon stackless threads and other async systems.

What does "I/O optimized scheduling" look like to you, and does it end up with the same sort of compiler hints, like "async / await"? Or is it different?

Re: Async Rust never left the MVP state

#228

Earlier quoted context omitted.

Can you elaborate on this please? Do you mean that’s basically impossible for rust std to provide a default runtime that makes “everyone” (embedded on one end and web on the other) happy?

I think that's the problem in essence, yes. Different executors built on top of different primitives and having different executions strategies will have mutually incompatible constraints. To spawn a future on tokio, it has to implement `Send`, because tokio is a work-stealing executor. That isn't the case for monoio or other non-work-stealing async executors, where tasks are pinned to the thread they are spawned on…

> To spawn a future on tokio, it has to implement `Send`, because tokio is a work-stealing executor.

Tokio's default executor is a work-stealing multi-threaded executor, but it also has a local executor and a current-thread executor, which can run !Send futures.

Re: Async Rust never left the MVP state

#229

Earlier quoted context omitted.

That’s part of it. Then you add a thread pool to dispatch your tasks into to mitigate the cost of a thread start. Then you run into blocking problems and are like “I wish I had some keyword to express when a function needed to be run on the thread pool”. Then you’ve done a speed run of the past 40 years of research.

The 40 years of research was actually in OS theory so that you could write normal code and async was abstracted away. A thread pool is not a research project.

Although they can be used in similar ways they work very differently.

* Cooperative vs. preemptive scheduling

* Userspace vs. kernel scheduling

* Stackless vs. stackful

* Easy control over waiting/blocking behavior vs. none

* Easy fan out + join vs. maybe, with some work and thread spawn overhead

* Can integrate within a single-threaded event loop vs. not really

Depending on what you're doing they may be interchangeable or you can only go one way. The basic cases where you're doing basically synchronous work in a thread/task is no different either way, other than having colored functioned with async/await and efficiency. If you're doing some UI work then event handlers are likely running in a single-threaded event loop which is the only thread you can interact with the UI on, which you can't block or the UI is going to freeze.

Re: Async Rust never left the MVP state

#230

Earlier quoted context omitted.

I think that callbacks are actually easier to reason about: When it comes time to test your concurrent processing, to ensure you handle race conditions properly, that is much easier with callbacks because you can control their scheduling. Since each callback represents a discrete unit, you see which events can be reordered. This enables you to more easily consider all the different orderings. Instead with threads it…

I agree. I don’t think callbacks are an underbaked language feature.

In another part of the thread, you lament the use of callbacks. May I ask you what you think async/await is, except syntactic sugar that wraps around the callback pattern?
Post reply on HN