News for hackers. Stuff that matters.
Re:Java Virtual Threads: A Case Study by fzeindl on Wednesday July 17, 2024 @12:45AM (#40982625)
Does it shake out to any real advantage?

To put it shortly: Writing single-threaded blocking code is far easier for most people and has many other benefits, like more understandable and readable programs: https://www.youtube.com/watch?v=449j7oKQVkc

The main reason why non-blocking IO with it's style of intertwining concurrency and algorithms came along is that starting a thread for every request was too expensive. With virtual threads that problem is eliminated so we can go back to writing blocking code.

Re:Java Virtual Threads: A Case Study by nlitened on Wednesday July 17, 2024 @01:21AM (#40982828)
> is far easier for most people

I’d say that writing single-threaded code is far easier for _all_ people, even async code experts :)

Also, single-threaded code is supported by programming language facilities: you have a proper call stack, thread-local vars, exceptions bubbling up, structured concurrency, simple resource management (RAII, try-with-resources, defer). Easy to reason and debug on language level.

Async runtimes are always complicated, filled with leaky abstractions, it’s like another language that one has to learn in addition, but with a less thought-out, ad-hoc design. Difficult to reason and debug, especially in edge cases

Re:Java Virtual Threads: A Case Study by xxs on Wednesday July 17, 2024 @03:11AM (#40983311)
>I’d say that writing single-threaded code is far easier for _all_ people, even async code experts :)

While 'async' is just a name, underneath it's epoll - and the virtual threads would not perform better than a proper NIO (epoll) server. I dont consider myself an 'async expert' but I have my share of writing NIO code (dare say not terrible at all)

Re:Java Virtual Threads: A Case Study by kaba0 on Wednesday July 17, 2024 @02:49PM (#40989053)
Virtual threads literally replace the “blocking” IO call issued by the user, by a proper NIO call, mounting the issuer virtual thread when it signals.
Re:Java Virtual Threads: A Case Study by bheadmaster on Wednesday July 17, 2024 @02:10AM (#40983043)
> Async runtimes are always complicated, filled with leaky abstractions, it’s like another language that one has to learn in addition, but with a less thought-out, ad-hoc design. Difficult to reason and debug, especially in edge cases

Async runtimes themselves are simply attempts to bolt-on green threads on top of a language that doesn't support them on a language level. In JavaScript, async/await uses Promises to enable callback-code to interact with key language features like try/catch, for/while/break, return, etc. In Python, async/await is just syntax sugar for coroutines, which are again just syntax sugar for CPS-style classes with methods split at each "yield". Not sure about Rust, but it probably also uses some Rust macro magic to do something similar.

Re:Java Virtual Threads: A Case Study by derriz on Wednesday July 17, 2024 @03:01AM (#40983264)
Indeed. Async runtimes/sytles are attempts to provide a more readable/useable syntax for CPS[1]. CPS originally had nothing to do with blocking/non-blocking or multi-threading but arose as a technique to structure compiler code.

Its attraction for non-blocking coding is that it allows hiding the multi-threaded event dispatching loop. But as the parent comment suggests, this abstraction is extremely leaky. And in addition, CPS in non-functional languages or without syntactic sugar has poor readability. Improving the readability requires compiler changes in the host language - so many languages have added compiler support to further hide the CPS underpinnings of their async model.

I've always felt this was a big mistake in our industry - all this effort not only in compilers but also in debuggers/IDE - building on a leaky abstraction. Adding more layers of leaky abstractions has only made the issue worse. Async code, at first glance, looks simple but is a minefield for inexperienced/non-professional software engineers.

It's annoying that Rust switched to async style - the abstraction leakiness immediately hits you, as the "hidden event dispatching loop" remains a real dependency even if it's not explicit in the code. Thus libraries using asycn cannot generally be used together although last time i looked, tokio seems to have become the de-facto standard.

[1] https://en.wikipedia.org/wiki/Continuation-passing_style

Re:Java Virtual Threads: A Case Study by kaba0 on Wednesday July 17, 2024 @02:47PM (#40989029)
I absolutely agree that the virtual/green thread style is much better, more ergonomic, less likely to be correct, etc, but I can’t fault Rust’s choice, given it being a low-level language without a fat runtime, making it possible to be called into from other runtimes. What the JVM does is simply not possible that way.
Re:Java Virtual Threads: A Case Study by logicchains on Wednesday July 17, 2024 @02:41AM (#40983161)
>Async runtimes themselves are simply attempts to bolt-on green threads on top of a language that doesn't support them on a language level.

Haskell supports async code while also supporting green threads on a language level, and the async code has most of the same issues as async code in any other languages.

Re:Java Virtual Threads: A Case Study by whateveracct on Wednesday July 17, 2024 @10:14AM (#40986186)
What problems exactly? Haskell has a few things that imo it does better than most languages in this area:

- All IO is non-blocking by default.

- FFI support for interruptible.

- Haskell threads can be preempted externally - this allows you to ensure they never leak. Vs a goroutine that can just spin forever if it doesn't explicitly yield.

- There are various stdlib abstractions for building concurrent programs in a compositional way.

Re:Java Virtual Threads: A Case Study by kbolino on Wednesday July 17, 2024 @05:53PM (#40990707)
> Haskell threads can be preempted externally - this allows you to ensure they never leak. Vs a goroutine that can just spin forever if it doesn't explicitly yield.

Goroutines are preemptible by the runtime (since https://go.dev/doc/go1.14#runtime) but they're still not addressable or killable through the language itself.

Re:Java Virtual Threads: A Case Study by whateveracct on Thursday July 18, 2024 @02:04AM (#40992892)
The GHC runtime has lots of cool concurrency features.

Async exceptions as a way to pass messages (and kill threads!)

Allocation limits for threads.

Software Transactional Memory.

Re:Java Virtual Threads: A Case Study by dwattttt on Wednesday July 17, 2024 @04:46AM (#40983733)
> Not sure about Rust, but it probably also uses some Rust macro magic to do something similar.

Much the same as JavaScript I understand, but no macros; the compiler turns them into Futures that can be polled

Re:Java Virtual Threads: A Case Study by chipdart on Wednesday July 17, 2024 @02:11AM (#40983048)
> To put it shortly: Writing single-threaded blocking code is far easier for most people and has many other benefits, like more understandable and readable programs:

I think you're missing the whole point.

The reason why so many smart people invest their time on "virtual threads" is developer experience. The goal is to turn writing event-driven concurrent code into something that's as easy as writing single-threaded blocking code.

Check why C#'s async/await implementation is such a huge success and replaced all past approaches overnight. Check why node.js is such a huge success. Check why Rust's async support is such a hot mess. It's all about developer experience.

Re:Java Virtual Threads: A Case Study by kitd on Wednesday July 17, 2024 @02:26AM (#40983109)
I think he was making the same point as you: writing for virtual threads is like writing for single-threaded blocking code.
Re:Java Virtual Threads: A Case Study by written-beyond on Wednesday July 17, 2024 @05:55PM (#40990711)
As someone who has written multiple productions services with Async Rust, that are under constant load, I disagree. I've had team members who have only written in C, pick up and start building very comprehensive and performant services in Rust in a matter of days.

How do you developers spew such strong opinions without taking a moment to think about what you're about to say. Rust cannot be directly compared to C#, Java or even Go.

You don't get a runtime or a GC with rust. The developer experience is excellent, you get a lot of control over everything you're building with it. Yes it's not as magical as languages and runtimes like you've mentioned, but the fact that I can at anytime rip those abstractions off and make my service extremely lightweight and performant is not something those languages will allow you to do.

And this is coming from someone who's written non blocking services before Async rust was a thing with just MIO.

The very fact Rust gets mentioned between these languages should be a tribute to the efforts of it's maintainers and core team. The amount of tooling and features they've added into the language gives developers of every realm liberty to try and build what they want.

Honestly, you can hold whatever opinion you want on any language but your comparison really doesn't make sense.

Re:Java Virtual Threads: A Case Study by Nullabillity on Wednesday July 17, 2024 @03:25AM (#40983366)
> To put it shortly: Writing single-threaded blocking code is far easier for most people. [snip] With virtual threads that problem is eliminated so we can go back to writing blocking code.

This is the core misunderstanding/dishonesty behind the Loom/Virtual Threads hype. Single-threaded blocking code is easy, yes. But that ease comes from being single-threaded, not from not having to await a few Futures.

But Loom doesn't magically solve the threading problem. It hides the Futures, but that just means that you're now writing a multi-threaded program, without the guardrails that modern Future-aware APIs provide. It's the worst of all worlds. It's the scenario that gave multi-threading such a bad reputation for inscrutable failures in the first place.