Live data from Hacker News

Async Rust never left the MVP state

tweedegolf.nl

201–210 of 273 posts

Re: Async Rust never left the MVP state

#201

Earlier quoted context omitted.

> So threads was the right programming model. It depends on what you are doing. Threads are the right model for compute-bound workloads. Async is the right model for bandwidth-bound workloads. Optimization of bandwidth-bound code is an exercise in schedule design. In a classic multithreading model you have limited control over scheduling. In an async model you can have almost perfect control over scheduling. A well-o…

If this is a classic exercise can you show me the material? Why can’t a scheduler be written which optimizes around IO? What additional information is present in code that has async/await annotations?

I believe that's actually how the virtual threads in the newer Java works. It's smart enough to notice IO and properly park it and move to another thread.

I think it's still basically doing epoll behind the scenes [1], but you have straightforward sequential code in the process and the actual implementation is invisible to the user, and you can use old boring blocking code with an object that is a drop-in replacement for Thread.

I personally still kind of prefer the explicit async stuff with Futures and Vert.x since I kind of like the idea that async is encoded into the type itself so you're more directly aware of it, but I'm definitely an outlier for that.

[1] Genuinely, please correct me if I'm wrong, it's very possible that I am.

Re: Async Rust never left the MVP state

#202

Earlier quoted context omitted.

Contrast it with async in JS/ES as an example... now combine it with the using statement for disposeAsync instances. await using db = await sqlite.connect(await ctx.getConfig("DB_CONN")); It's not so bad when you have one `await foo` vs `foo.await`, it's when you have several of them on a line in different scopes/contexts. Another one I've seen a lot is... const v = await (await fetch(...)).json(); Though that could…

I’ve never in my life used JS, so I’ll have to take your word for it.

It's a language I'm familiar with that uses the `await foo` syntax and often will see more than one in a line, per the examples given. C# is the most prominent language that has similar semantics that I know well, but is usually less of an issue there.

Re: Async Rust never left the MVP state

#203
post #182
post #89

Earlier quoted context omitted.

As you mentioned Java, it’s interesting to notice that it has had similar problems throughout its history: logging (now it’s settled on slf4j but you still find libraries using something else), commons (first Apache Commons, now Guava), JSON (it has settled on Jackson but things like Gson and Simple-json are not uncommon to see), nullability annotations ( first with unofficial distributions of JSR-305 which never bec…

commons, is something that is eventually being migrated into the main, at least those that are decided to be required for most projects. I don't use apache commons or guava at all in java (now at 25 or 26, depending on project) - there are still some libs that depend on those, but I would argue that most use it out of inertia, than actual need. As for slf4j, I still don't see any justification for an abstraction laye…

The logging implementation should be an application level decision. By using a facade like slf4j a library allows an application using any logging implementation to use it. That’s why libraries should use it.

Re: Async Rust never left the MVP state

#204

what's the modern "absolute beginner's guide to async in Rust" - ideally something dense that can bring someone motivated from beginner to expert in ~1 week of intense hacking on it?

It doesn't take a week to learn the async basics. add async keyword to functions add .await when calling them use tokio in your main function (easy to look up) use the async recursion crate if you need to use recursion but don't want to box everything There are some bonuses like calling functions in parallel, but there you go.

And then you want to do something trivial like an async callback

Re: Async Rust never left the MVP state

#205

Earlier quoted context omitted.

Why can’t you do the same optimization? Are you maxing out you OS system resources on thread overhead?

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.

Re: Async Rust never left the MVP state

#206

I like it more how Zig is approaching async with the new IO. It avoids function coloring.

Does it, though? Whether your function has the `async` keyword attached or has a function argument of type `IO` doesn't really change anything substantial. The whole "function color" argument seems pretty overblown to me. You can't call `foo(int, string)` if you don't have both an int and a string, so is it now a different "color" than the function `bar(int)`? If you want to call `foo` from `bar`, you have to somehow…

Yeah, I tend to agree. What does improve quality-of-life substantially is having a proper effect system, especially when it comes to composing higher-order functions.

Having to write copies of List.map and List.async_map in the stdlib is a smell, but the real cost is potentially having to duplicate every function in your code that calls either.

E.g, if you have the 'async' effect, List.map can work with async functions or synchronous ones, without modification. It's the caller's responsibility to provide that async handler/environment at whatever level of abstraction makes sense, instead of explicitly wiring IO or async all the way through for a function that may or may not need it. The compiler (or runtime, if necessary) will keep you from calling a function that requires the async effect if you don't have a handler for it.

Re: Async Rust never left the MVP state

#207
post #167

Earlier quoted context omitted.

> 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 Not really. I’ve observed async code often is written in such a way that it doesn’t maximize how much concurrency can be expressed (eg instead of writing “here’s N I/O operations to do them all concurrently” it’s “for operation X, await process(x)”). However, in a threaded wor…

> work stealing executors have long been known to offer significantly lower latency with more consistent P99 than traditional threads. This has been known since forever - in the early 00s Well, we know how to make "traditional threads" fast, with lower latency and more consistent P99 since forever^2, in the early 90s. [1] Sure, we can't convince that Finnish guy this is worthwhile to include in THE kernel, despite si…

[deleted]

Re: Async Rust never left the MVP state

#208
post #3

Earlier quoted context omitted.

Agree on title. Too dramatic. The author seems to be obsessing about the overhead for trivial functions. He's bothered by overhead for states for "panicked" and "returned". That's not a big problem. Most useful async blocks are big enough that the overhead for the error cases disappears. He may have a point about lack of inlining. But what tends to limit capacity for large numbers of activities is the state space req…

He's optimizing for embedded no-std situation. These things do matter in constrained environments.

He briefly mentions microcontrollers, but doesn't go into details. That might make sense, for microcontrollers which implement some kind of protocol talking to something.

Re: Async Rust never left the MVP state

#209

Earlier quoted context omitted.

> What's the alternative? Traits in the stdlib for common functionality like "spawn" (a task) and things like async timers. Then executors could implement those traits and libraries could be generic over them.

Good point, but the devil lies in the details. How should the timers behave? Is the clock monotonic? Are tasks spawned on the same thread? Different platforms and executors have different opinions. Maybe it's still possible and just a lot of work?

>the devil lies in the details

This is true, but perhaps not uniquely so, when compared to platform dependence of the standard libary already. File semantics, sync primitive gaurantees and implementations, timers and timer resolutions, etc have subtle differences between platforms that the Rust stdlib makes no further gaurantees about.

Post reply on HN