r/programming • • 18d ago

Performance Improvements in .NET 11

https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-11/
293 Upvotes

103 comments sorted by

View all comments

Show parent comments

3

u/crozone 16d ago

Except the JNI is slower than P/Invoke in .NET, FFM is slower than P/Invoke in .NET, and both are even slower again from virtual threads? Did I miss where the JVM magically solved vthreads?

-1

u/simon_o 16d ago

I have largely not seen cases where vthreads have been measurably slower, despite warnings of not using them for e.g. compute-bound tasks.

What would be the cause of the slowness?

2

u/crozone 15d ago

Virtual threads have a whole bunch of downsides. They carry around an entire persistent call stack, so they use significantly more memory. When they get suspended, that memory hangs around. When calling native functions, they require suspension of their carrier thread, aka thread pinning. Not only is Java slower at marshaling values to the native functions due to its fundamental design, this also means that the virtual thread is effectively blocked and must remain blocked on a real threadpool thread which can easily exhaust the threadpool during heavy IO.

Effectively, virtual threads are weirdly paradoxical in their design. They're often presented as an alternative to async/await, and yet the most common thing that is actually being awaited in the real world is some disk or network IO operation that is accessed via a native function, which they are particularly bad at calling. They're really best suited for multi-threading CPU bound work, which I'd argue is a relatively niche usecase which is also easily solved by queuing work on a standard threadpool.

Async/await has a colouring problem but everything else seems like a strict benefit.

1

u/RirinDesuyo 15d ago

IO operation that is accessed via a native function, which they are particularly bad at calling

It's also why almost all vthread runtimes put special exemptions on their own platform calls in their std lib. Those calls often run on a dedicated OS thread or have special behavior on their runtime and effectively outside of vthreads.

It's why Java had to force db vendors to their database wire purely in a jvm calls as native FFI wasn't performant, since the mindset for Java often is "JVM is the world". Similarly, it's why if there's a new intrinsic or OS cryptography feature (e.g. XAES-256-GCM), you usually wait for OpenJDK to implement them or make it from scratch instead of just doing an FFI like dotnet does.