Live data from Hacker News

Project Loom and Structured Concurrency

javaadvent.com

61–70 of 111 posts

Re: Project Loom and Structured Concurrency

#62
`Async`/`await` or something like Kotlin's `suspend` are great language features for certain domains in which a developer needs to manage blocking system calls: in lower-level languages such as Rust or C, you probably don't want to pay for a lightweight "task runtime" Like Go's or Erlang's. They bring not only a scheduling overhead but also FFI complications.

However, for application languages that can afford a few extra nicities like garbage collection, I fail to understand why the stackless coroutine model (`suspend` in Kotlin) or `async`/`await` continue to be the developer's choice. Why do languages like Kotlin adopt these features, specifically?

Manually deciding where to yield in order to avoid blocking a kernel thread seems outside of the domain of problems that those using a _higher level_ language want to solve, surely?

The caller should decide whether to do something "in the background". And this applies to non-IO capabilities too, as sometimes pure computations are also expensive enough to warrant not blocking the current task.

Go and Erlang seem to have nailed this, so I'm glad Java is following in their footsteps rather than the more questionnable strategy of C# and Kotlin. (Lua's coroutines and Scheme's `call-with-current-continuation` deserve an honourable mention too.)

Re: Project Loom and Structured Concurrency

#63

Earlier quoted context omitted.

Originally (about 20 years ago) java threads were M:N I think. How is this different? If I had to guess, they are not opaque to the VM which has more freedom to optimize them.

This is mentioned in the article: the old green threads model was not blocking aware - if a green thread scheduled on an OS thread issued a blocking call (say a listen on a socket) than the whole OS thread was blocked. With Project Loom, if a virtual thread executes a blocking call, the virtual thread is suspended and the OS thread is free to execute another virtual thread.

So how does it actually execute the system call under the hood? Using some kind of background OS thread pool?

Re: Project Loom and Structured Concurrency

#64
post #31

I have a lot of experience using concurrency in Go, and for the last couple years have been at the bleeding edge of Python async. The tradeoffs between the two approaches are immense. With the virtual thread model you have: * No function coloring problem. This also means existing code is easier to port. * possibility of transparent M:N scheduling. * Impedence mismatch with OS primitives. * Much more sophisticated run…

* Java offers both user-mode and kernel threads. You pick at creation, and can even plug your own scheduler. * Loom's virtual threads are completely scheduled in library code, written in Java. * FFI that bypasses the JDK and interacts with native code that does either IO or OS-thread synchronization is extremely rare in Java. * Cancellation is the same for both. Also, IMO, coordination is simpler for threads than for…

One headache I see that no one seems to mention is thread affinity seems a lot harder to manage in an implicit system. Many patterns use a single thread for synchronization but often times one thread is special. UI systems often have a UI thread that controls the GLContext or what have you. In something like C#'s async, you can easily schedule tasks off and on that thread. I'm not sure how you could do this implicitly. Loom seems to keep around native Threads for this sort of thing?

I would be really interested in seeing a UI system written with Loom.

>FFI that bypasses the JDK and interacts with native code that does either IO or OS-thread synchronization is extremely rare in Java.

I would also argue its rare because its hard to do. This is a self fulfilling argument. In C#, a very similar language, its much more common to do that sort of thing because its easier. C# is chosen for games and other apps because it can interop with native more easily.

Re: Project Loom and Structured Concurrency

#65

`Async`/`await` or something like Kotlin's `suspend` are great language features for certain domains in which a developer needs to manage blocking system calls: in lower-level languages such as Rust or C, you probably don't want to pay for a lightweight "task runtime" Like Go's or Erlang's. They bring not only a scheduling overhead but also FFI complications. However, for application languages that can afford a few e…

Kotlin runs on JVM so if JVM does not support something natively Kotlin can't have that feature like task runtime.

Re: Project Loom and Structured Concurrency

#66
post #59
post #57

Earlier quoted context omitted.

Fair point about the abstraction level of a Java thread vs an OS thread. In light of both things you just wrote, let me ask you this: why does Java give us any choice on thread implementation? Why not have everything be a green thread from now on? If Java threads are not OS threads, can be paused for any amount of time, and there's no reason that network calls or db calls or file IO should be treated any differently,…

The first part of the answer is the same as that for a similar question we've been asked about LinkedList: we don't deprecate things that are heavily used, however useless or superseded by something else, unless they are very harmful. Deprecation in Java does not mean "unrecommended" but "absolutely do not use this if you want your program to continue working on future versions." Not only is it a compile-time warning…

Are virtual threads preemptable? If not, then one use for OS threads is when running a bunch of compute intensive tasks and you don't want worry about stalling everything else. I suppose in that case you could just use a separate executor for those expensive tasks. I wonder how many devs will spawn tasks using the default executor and then wonder why things aren't working out so well? Will there be tooling to help identify such issues?

Re: Project Loom and Structured Concurrency

#67
post #65

`Async`/`await` or something like Kotlin's `suspend` are great language features for certain domains in which a developer needs to manage blocking system calls: in lower-level languages such as Rust or C, you probably don't want to pay for a lightweight "task runtime" Like Go's or Erlang's. They bring not only a scheduling overhead but also FFI complications. However, for application languages that can afford a few e…

Kotlin runs on JVM so if JVM does not support something natively Kotlin can't have that feature like task runtime.

Additionally Kotlin also targets native. `suspend` in Kotlin was very much designed with this in mind as it's easier to implement than something that requires an extensive runtime like Loom.

Kotlin will still support Loom on JVM and there will likely be integration with suspend/flows etc also.

Re: Project Loom and Structured Concurrency

#68

I have a lot of experience using concurrency in Go, and for the last couple years have been at the bleeding edge of Python async. The tradeoffs between the two approaches are immense. With the virtual thread model you have: * No function coloring problem. This also means existing code is easier to port. * possibility of transparent M:N scheduling. * Impedence mismatch with OS primitives. * Much more sophisticated run…

A couple of excellent articles on the different ways of thinking about the choice (of when to yield) vs. color (virality of choice) problem:

* Choice is bad: https://journal.stuffwithstuff.com/2015/02/01/what-color-is-... * Choice is good: https://glyph.twistedmatrix.com/2014/02/unyielding.html

Re: Project Loom and Structured Concurrency

#69
post #66
post #59

Earlier quoted context omitted.

The first part of the answer is the same as that for a similar question we've been asked about LinkedList: we don't deprecate things that are heavily used, however useless or superseded by something else, unless they are very harmful. Deprecation in Java does not mean "unrecommended" but "absolutely do not use this if you want your program to continue working on future versions." Not only is it a compile-time warning…

Are virtual threads preemptable? If not, then one use for OS threads is when running a bunch of compute intensive tasks and you don't want worry about stalling everything else. I suppose in that case you could just use a separate executor for those expensive tasks. I wonder how many devs will spawn tasks using the default executor and then wonder why things aren't working out so well? Will there be tooling to help id…

> Are virtual threads preemptable?

Yes, but the preemption operation is not currently publicly exposed. We're considering whether and how to expose it.

> I wonder how many devs will spawn tasks using the default executor and then wonder why things aren't working out so well? Will there be tooling to help identify such issues?

What those issues would actually be, in practice, is still unclear, hence our reluctance to expose forced preemption. People rely on OS time-sharing (what you call preemption) inside applications far less than they think. No scheduling algorithm can make a program that requires more processing resources than available to run well.

Re: Project Loom and Structured Concurrency

#70
post #67
post #65

Earlier quoted context omitted.

Kotlin runs on JVM so if JVM does not support something natively Kotlin can't have that feature like task runtime.

Additionally Kotlin also targets native. `suspend` in Kotlin was very much designed with this in mind as it's easier to implement than something that requires an extensive runtime like Loom. Kotlin will still support Loom on JVM and there will likely be integration with suspend/flows etc also.

That's a good point. Generally, I opt for languages that either compile away their nicities to avoid runtime hits, such as Rust being compiled to WASM, or languages that bring nicities in runtimes that they _completely own_, such as Java on the JVM.

The problem with Kotlin and the like is that they can't easily compile away their features due to inherent runtime dependencies, e.g. garbage collection, making them poorly suited to environments with a very minimal runtime like WASM, while also being at the mercy of the host language creating runtime abstractions that have mismatches with their own language's features.

Although it'd be unfair for me to say the JVM is designed only for Java; invokedynamic and non-reified generics both assist JVM targetting for non-Java languages such as Clojure.

Post reply on HN