-
Notifications
You must be signed in to change notification settings - Fork 3.6k
feat: virtual thread executor support #32689
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
akka-actor/src/main/scala/akka/dispatch/VirtualThreadConfigurator.scala
Outdated
Show resolved
Hide resolved
akka-actor-tests/src/test/scala/akka/dispatch/VirtualThreadDispatcherSpec.scala
Outdated
Show resolved
Hide resolved
akka-actor/src/main/scala/akka/dispatch/VirtualThreadConfigurator.scala
Outdated
Show resolved
Hide resolved
throw new IllegalStateException("Virtual thread executors only supported on JDK 21 and newer") | ||
} | ||
val ofVirtual = ofVirtualMethod.invoke(null) | ||
// java.lang.ThreadBuilders.VirtualThreadBuilder is package private |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would you write this without reflection?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't the public way like this?
ThreadFactory virtualThreadFactory = Thread.ofVirtual().factory();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that's what we are calling here, with a potential name inbetween Thread.ofVirtual().name(virtualThreadName).factory()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify the comment, the reason why we can't just do ofVirtual.getClass.getMethod("name")
is that it is of a package private type, so we need to look up the interface it implements that has the name
method instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking we could use Thread.Builder.OfVirtual
, which is the public type. I think this should work:
val ofVirtual = ofVirtualMethod.invoke(null)
val nameMethod = classOf[Thread.Builder.OfVirtual].getMethod("name", classOf[String])
nameMethod.invoke(ofVirtual, virtualThreadName)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thread.Builder.OfVirtual
only exists on JDK 21 and later so we can't do classOf[Thread.Builder.OfVirtual]
and have the code still compile on 11 and 17
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, above comment about ThreadBuilders.VirtualThreadBuilder
was misleading me. I thought you reached out for that one. You are already using the one that I suggested.
val ofVirtualInterface = dynamicAccess.getClassFor[AnyRef]("java.lang.Thread$Builder$OfVirtual").get
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I'll drop the comment, it's not needed and worse if it is confusing :)
…t for blocking io dispatcher
akka-actor/src/main/scala/akka/dispatch/AbstractDispatcher.scala
Outdated
Show resolved
Hide resolved
For the record, here are some results of ActorBenchmark comparing direct JFP with virtual threads to see the overhead (Linux, 12 core x86 intel i5):
I've also run a benchmark looking at gc, sadly did not save the output, but alloc rate up from 0.001 B per op to 0.309 B, not scaled with troughput: 27mb/s for FJP up to 48mb/s with virtual thread per task, this leads to around 10% more time spent on GC. This proves that it is maybe not a good default default dispatcher for actors, however for a blocking io dispatcher that will anyway have a much lower throughput, mostly waiting for some blocking task, it seems like a reasonable tradeoff. |
throw new IllegalStateException("Virtual thread executors only supported on JDK 21 and newer") | ||
} | ||
val ofVirtual = ofVirtualMethod.invoke(null) | ||
// java.lang.ThreadBuilders.VirtualThreadBuilder is package private |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking we could use Thread.Builder.OfVirtual
, which is the public type. I think this should work:
val ofVirtual = ofVirtualMethod.invoke(null)
val nameMethod = classOf[Thread.Builder.OfVirtual].getMethod("name", classOf[String])
nameMethod.invoke(ofVirtual, virtualThreadName)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, with possibly changing misleading comment
throw new IllegalStateException("Virtual thread executors only supported on JDK 21 and newer") | ||
} | ||
val ofVirtual = ofVirtualMethod.invoke(null) | ||
// java.lang.ThreadBuilders.VirtualThreadBuilder is package private |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, above comment about ThreadBuilders.VirtualThreadBuilder
was misleading me. I thought you reached out for that one. You are already using the one that I suggested.
val ofVirtualInterface = dynamicAccess.getClassFor[AnyRef]("java.lang.Thread$Builder$OfVirtual").get
This adds a new executor config which will make a dispatcher run each scheduled task as a separate, new, virtual thread. This is very useful for blocking logic, for example in futures, but less so for running actors on and has considerable overhead for message intense systems.
Somewhat related issue #31613