Java threads including Virtual Threads (JDK 21+) are preemptive.
They are not - and do not claim to be preemptive. They claim they are "not cooperative", but even that doesn't mean what anyone else thinks it means. This paragraph is the only one containing the word "preempt" in JEP 444: "The scheduler does not currently implement time sharing for virtual threads. Time sharing is the forceful preemption of a thread that has consumed an allotted quantity of CPU time. While time shar…
How did we get to that?
We were talking about n:m threading, especially with threads being blocking IO-aware, being able to automagically turning such a call to non-blocking. Java more than fits that description.
Three things stick out to me on https://gossamer-lang.org/docs/migration/rust/ * No user macros at all. Six fixed format! / println!-family macros expand at parse time. - Meta programming is incredibly important in rust. * (unsafe is) Forbidden at the language level. No unsafe keyword in Gossamer source. std is safe-Rust too. - No low level programming then. * No move semantics. Non-trivial values are heap-allocated,…
All three points are erased by its ability to call Rust functions… It’s not a bad approach, in that for most general programming one doesn’t need those things. Granted, macros can be convenient.
Any language with FFI support can call rust functions.
> why do languages like Crystal and D still use Boehm? Languages use Boehm for exactly one reason: it is easy to shim into an otherwise manual memory system (it was designed for use in C/C++). I mean no respect to its authors, but using Boehm in production is the worst of all worlds: slow allocations (free list allocator), poor cache locality, and not precise (so you can expect memory leaks). If you are going to do a…
This is all true but is a somewhat Java-flavoured perspective i.e. generations ties you into a moving collector, which ties you into barriers and complicates FFI, which is not always the right tradeoff. A non-fragmenting allocator goes a long way to alleviating the need for compactions too.
Not necessarily Java-flavored, but internally vs externally focused, yes. More difficult FFI assuming that is the exception not the rule, and that the language itself takes precedence. Write barriers are also not a given if using segmented heaps. Many ways to do this and no single right way. Memory allocation scheme isn't something that is just bolted on, but needs to be aligned to the rest of the language. For example, Java needs such fast allocations and good GC because it does almost no inline allocation whatsoever, so without the best GC on the planet, it would be a lot slower than it is. Contrast this with Go, which has a solid amount of inline allocations, and hence, can get by with a much slower allocator (~3-4x slower by my measurements) and a more basic mark-sweep allocator since the memory pressure is solidly less.
They are not - and do not claim to be preemptive. They claim they are "not cooperative", but even that doesn't mean what anyone else thinks it means. This paragraph is the only one containing the word "preempt" in JEP 444: "The scheduler does not currently implement time sharing for virtual threads. Time sharing is the forceful preemption of a thread that has consumed an allotted quantity of CPU time. While time shar…
How did we get to that? We were talking about n:m threading, especially with threads being blocking IO-aware, being able to automagically turning such a call to non-blocking. Java more than fits that description.
The original message you replied to said (mistakenly):
> adopt true goroutines
Goroutines are preemptive. The distinction between cooperative and non-cooperative concurrency is very significant - it is the difference between never having to think about the scheduler and always having to thinking about it when doing CPU intensive tasks.
Haskell does too. And it predates Go by a large margin, such that calling it goroutine is weird. And within Google, the C++ implementation fiber also predated goroutines. It really shows that this is more of a library feature rather than a language feature.
I agree with your objection to treating goroutines as the baseline implementation of fibers. However, I would disagree with categorizing the feature as a library feature vs a language level feature. In “low-level” languages (C, Rust, Zig, C++, etc) the ability and option exists for having ‘green threads’ with most of their commonly assumed characteristics be library based constructs (although see [1] for why that’s n…
We are not disagreeing here. Your citation is actually not relevant: Boehm is arguing that you cannot implement threads as libraries in a language without threading. But all modern languages actually have OS native threads; the addition of green threads to this environment does not require any further changes to the compiler in addition to what has been changed to support OS threads. If anything, green threads are even easier to support than real OS threads depending on the preemption design.
@LoganDark You're right, as long as there is an object graph to scan, 'uncontrollable' latency is an inherent trade-off in GC-based systems. I’ve taken a different route with a C++20 execution engine that eliminates the object graph scan entirely by using pre-allocated, static memory pools and lock-free SPSC structures. It's essentially moving from 'managing GC pauses' to 'deterministic, zero-allocation execution'. H…
The lock-free architecture that bypasses the allocator on the hot path is called `alloca`. Many mainstream compilers, and nearly every language that is not C, seemingly haven't properly supported it for years.
Please don't twist. alloca is in fact a limited arena/pool allocator and as such for some small sizes it is latency-free. It is also there in C. It does not have anything to do with GCs.
You insist that offloading other allocations to a GC running on other threads somehow grants the current thread control over its own scheduling.
This is false.
One can say that you can't really control latency unless running under a RTOS and thus we shall never attempt that. This is also false.
There is no conceivable reason one should not assert absolute control upon what his own code does. GC injects uncertainity into that. This is intolerable.
All three points are erased by its ability to call Rust functions… It’s not a bad approach, in that for most general programming one doesn’t need those things. Granted, macros can be convenient.
Any language with FFI support can call rust functions.
My impression was that Gossamer has good Rust FFI rather than basic C FFI, sharing struct layout etc. I may play around with Gossamer and see how it really does performance wise…
The syntax similarities help make for a more painless two language approach.
The lock-free architecture that bypasses the allocator on the hot path is called `alloca`. Many mainstream compilers, and nearly every language that is not C, seemingly haven't properly supported it for years.
Please don't twist. alloca is in fact a limited arena/pool allocator and as such for some small sizes it is latency-free. It is also there in C. It does not have anything to do with GCs. You insist that offloading other allocations to a GC running on other threads somehow grants the current thread control over its own scheduling. This is false. One can say that you can't really control latency unless running under a…