Live data from Hacker News

Project Loom and Structured Concurrency

javaadvent.com

71–80 of 111 posts

Re: Project Loom and Structured Concurrency

#71
post #19

Earlier quoted context omitted.

It's like saying the article goes out of its way not to mention Scala/Haskell's IO type. Syntactic coroutines, monadic IO, and threads are different constructs, although they are different ways to address a similar problem -- expressing sequential (and, in contrast, parallel) composition. Virtual threads are Java threads; there's nothing "bolted". Syntactic coroutines are a kind of syntactic code-unit similar to subr…

It's more than that. Java developers are switching to Kotlin; notably on Android and Spring code bases (well over 50% of backend Java projects at this point apparently). This is an article about structured concurrency and how Loom implements something that Kotlin has shipped that both Android and Spring heavily integrate with already. So, there's more than a casual relation between Kotlin co-routines and Loom. I'd go…

> notably on Android and Spring code bases

Of course they are, on Android, Google is doing everything that they can to push Kotlin down developer throats, most Java developers end up moving to Kotlin when the option is an half baked implementation of Java, called Android Java, stuck in Java 8, when we are already on Java 15, and Google is unwilling to move Java support any further than what they are forced to due to InteliJ own changes.

Spring, well they only care about marketing and getting Spring sales, I still remember when Groovy was supposed to take over the Java world and also had first class support in Spring, just like they are selling Kotlin nowadays.

I got some nice consulting gigs porting those projects back to Java, and the same will happen with Kotlin projects when Google gets fed up with Android and moves on to Fuchsia/Flutter.

Re: Project Loom and Structured Concurrency

#72

I don't quite get the point of the executor service with virtual threads. If they are really cheap to create then why not just create them as required? It's been a while since I programmed in Java though, am I missing something? Edit: Ah - I read the rest of the article. Using it as a synchronisation primitive makes sense I guess, if a bit clunky.

It is an unfortunate abuse of an existing facility for something quite different.

The API is not yet final, but I wonder why you think it's "an abuse of an existing facility for something quite different," and whether this could just be a matter of a habit rather than purpose.

Take a look at the description of ExecutorService (https://docs.oracle.com/en/java/javase/15/docs/api/java.base...) and Executors (https://docs.oracle.com/en/java/javase/15/docs/api/java.base...). I think we're using them exactly as intended: those are APIs meant to manage and control task's execution and lifetime. I'm interested to hear why this feels wrong to you.

Re: Project Loom and Structured Concurrency

#73

Earlier quoted context omitted.

> Since the article goes out of its way to not mention Kotlin, "Since the article goes out of its way to not mention [Rust|Kotlin]" and "I'm surprised this article has no mention of [Rust|Kotlin]" must be one of the most frequently used templates on HN.

The difference is that Kotlin has been gobbling up Java users using Java frameworks like Android and Spring. Coroutines are used in both and implement structured concurrency exactly like Loom does. It's not a little bit similarish and vaguely related: it maps 1 to 1 conceptually; well at least for the stuff that Loom actually implements. Rust indeed would deserve a mention as well but it follows a somewhat different…

Kotlin is just yet another guest language on the JVM, written in a mix of Java, C++, no Kotlin code around, neither today nor tomorrow.

Google is pushing Kotlin as hard as they can on Android, while leaving Android Java dialect stagnate on a pseudo Java 8 compatibility, they have a political agenda to play here.

Spring just goes after any shiny thingie that might bring users into their domain, Groovy, Clojure, Scala, and now Kotlin.

Re: Project Loom and Structured Concurrency

#74
post #64
post #31

Earlier quoted context omitted.

* 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 implicitl…

> I'm not sure how you could do this implicitly.

See https://news.ycombinator.com/item?id=25301246

> I would also argue its rare because its hard to do.

I would argue it's mostly because the Java ecosystem is so rich (often richer than "native" alternatives), there's hardly ever a need to do it. BTW, as of JDK 16, you'd be able to do FFI in pure Java: https://openjdk.java.net/jeps/389 It's not yet entirely convenient -- that would come later.

Re: Project Loom and Structured Concurrency

#75
post #45
post #40

Earlier quoted context omitted.

You're getting downvoted because of your snarky opening statement. But I do think it's important/relevant to compare virtual threads to Kotlin coroutines. I agree with your point that tacking all of this onto the existing (flawed) Thread API is a risky move. I understand the reasoning on both sides, but I'm not usually a huge "backwards compatible at all costs" or "don't make people learn new things" proponent on any…

> I agree with your point that tacking all of this onto the existing (flawed) Thread API is a risky move. This is not what Loom does, though. Virtual threads are not using the thread API. They are (Java) threads; no more and no less than today's threads. Just as people don't normally use the java.lang.Thread API directly to use today's threads, there's no reason why they should use it with virtual threads. > One adva…

They are threads in the same way that Java's original green threads were threads and in exactly the same way that co-routines are user scheduled thread like objects. They are not proper OS threads scheduled by the OS. Kotlin's co-routine implementation does something very similar and will just use a Loom thread when that becomes available.

It will also use executors with multiple threads if you use the right dispatcher.

I'm not sure I get your point about colored functions. Under the hood the compiler generates what is basically a callback structure not unlike what you get in javascript (i.e. a promise). It gains features like callback hierarchies, cancellation, etc. Loom fixes this by forcing you to wrap things with a Thread. Same kind of mental overhead.

Re: Project Loom and Structured Concurrency

#76
post #34

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…

I don't think "task cancellation" is quite the major difference you think. If you model it as thread A wants to cancel thread B, then while threading means that A runs and cancels B, but B may need some time to catch up, the async world has the problem of thread A running at all to cancel B, if B is having a problem that requires cancellation. It's "obvious" and "safe" until it doesn't happen at all. This is a pervas…

If Loom isn't adding cancellation tokens to the core library then its going to be a major difference. That said, the Java way was already for runnables to cancel themselves with some kind of volatile cancel bool so I expect that's all we'll get.

From the article: >Clearly the intent is also to cancel the child thread. And this is exactly what happens.

I find this to be a bold choice. In C# you can detach children and such. Should be interesting to see if this gets added later.

Re: Project Loom and Structured Concurrency

#77
post #34

Earlier quoted context omitted.

I don't think "task cancellation" is quite the major difference you think. If you model it as thread A wants to cancel thread B, then while threading means that A runs and cancels B, but B may need some time to catch up, the async world has the problem of thread A running at all to cancel B, if B is having a problem that requires cancellation. It's "obvious" and "safe" until it doesn't happen at all. This is a pervas…

Async, and cooperative multitasking in general, requires all members participate in the contract: you shall not block and you shall not go too long until yielding. Once a piece of code violates that, all bets are off. Python has explicit debugging mechanisms to help a developer detect the latter. Cancel safety is less about killing an out-of-control task, and more about making sure the state after cancelling a task i…

>you shall not block and you shall not go too long until yielding

Eh... you as the caller have control on how a task is run. If you want it on a different thread and non-blocking, or simply deferred, you can. You have a lot of control.

With an implicit system you have much less control. Loom seems to solve this by letting you explicitly schedule tasks anyhow?

Re: Project Loom and Structured Concurrency

#78

Earlier quoted context omitted.

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?

From what I can tell, async system calls are used whenever possible. A blocking call on a socket doesn't make a blocking system call, thus permitting the carrier OS thread to go do something else. As for file I/O, things are a bit messy. Older linux kernels don't support "true" async file I/O, and the Java NIO async file channels do use thread pools to emulate async behavior in that case.

Re: Project Loom and Structured Concurrency

#79
post #30

For me the real advantage is not on performance but on the programming model. I have been tinkering with Loom (and clojure) and the idea of "just" calling some library without worrying about blocking is refreshing. That means that for the most of it, you can write your code without worrying too much about some kind of callbacks or async support from your library and it just works. Of course, for those with extreme pe…

I think the vast majority of JVM users won't even need Loom. OS threads perform well enough for most use cases. You can go a very long way with just a ThreadPoolExecutor.

No one “needs” Loom; you can always write in callback oriented style. The point is it will free you from that.

Re: Project Loom and Structured Concurrency

#80
post #45

Earlier quoted context omitted.

> I agree with your point that tacking all of this onto the existing (flawed) Thread API is a risky move. This is not what Loom does, though. Virtual threads are not using the thread API. They are (Java) threads; no more and no less than today's threads. Just as people don't normally use the java.lang.Thread API directly to use today's threads, there's no reason why they should use it with virtual threads. > One adva…

They are threads in the same way that Java's original green threads were threads and in exactly the same way that co-routines are user scheduled thread like objects. They are not proper OS threads scheduled by the OS. Kotlin's co-routine implementation does something very similar and will just use a Loom thread when that becomes available. It will also use executors with multiple threads if you use the right dispatch…

> I'm not sure I get your point about colored functions. Under the hood the compiler generates what is basically a callback structure not unlike what you get in javascript (i.e. a promise). It gains features like callback hierarchies, cancellation, etc. Loom fixes this by forcing you to wrap things with a Thread. Same kind of mental overhead.

The difference is that I'm not allowed to pull apart the callback structure that colored functions (in Kotlin) cause the compiler to make. Instead, I just have a colored function I have to work with. And it's incompatible (in one direction) with functions of the wrong color.

Colored functions don't compose well. The green thread approach allows you to call anything from anywhere and compose whatever you want. When you choose to make it asynchronous, then you wrap it in a green thread and fire it off. That's pretty different than having two juggle different colored functions AND still needing to fire them off via whatever coroutine laucher.

Post reply on HN