Skip to content

Commit 76d2253

Browse files
committed
1st cut vthreads doc
1 parent f191fb5 commit 76d2253

File tree

1 file changed

+37
-0
lines changed

1 file changed

+37
-0
lines changed

doc/vthreads.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# core.async and virtual threads
2+
## Rationale
3+
4+
Java 21 saw the inclusion of [virtual threads](https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html). Virtual threads were added to address the limitations of platform threads for handling highly-concurrent, I/O heavy workloads. While core.async provided mechanisms for mapping operations to platform threads, their limitations were absorbed by the library itself. That is, the granularity of workflow profiles that core.async could directly support were limited by those supported by platform threads and its internal IOC mechanisms. By enhancing core.async to use virtual threads for workloads in which they excel, we can open up new execution modes supported by the best-fit threading modes in the JVM.
5+
6+
## Workload types
7+
8+
Traditionally, core.async implicitly supported two workload types:
9+
10+
- Channel dispatch workloads implicit to the `go` block IOC completion handling and thunk processing, backed by a user-configurable bounded thread-pool
11+
- User-specific workloads backed by platform threads created with the `clojure.core.async/thread` macro
12+
13+
As a first step toward integrating virtual threads, we changed the underlying workflow model within core.async to support a richer set of types, each described via related keywords:
14+
15+
- `:io` - used in the new `clojure.core.async/io-thread` macro for `:io` workloads in flow/process, and for dispatch handling if no explicit dispatch handler is provided (see below)
16+
- `:mixed` - used by `clojure.core.async/thread` and for `:mixed` workloads in flow/process
17+
- `:compute` - used for `:compute` workloads in flow/process
18+
- `:core-async-dispatch` - used for completion fn handling (e.g. in `clojure.core.aync/put!` and `take!`, as well as go block IOC thunk processing) throughout core.async.
19+
20+
The defaults and mechanisms for customization around these workloads are described later.
21+
22+
## core.async's use of virtual threads
23+
24+
By default, whenever core.aync runs in an environment that supports virtual threads (i.e. a version 21+ JVM), it will use virtual threads to service all `:io` workloads executed with the `io-thread` macro. Additionally, all `go` IOC dispatching will use virtual threads under the hood.
25+
26+
### Specifying a factory for custom thread `ExecutorService` instances
27+
28+
However, to support a graceful upgrade path for core.async users, we've added mechanisms to customize if and how virtual threads are used. First, the Java system property `clojure.core.async.executor-factory` specifies a function that will provide `java.util.concurrent.ExecutorService`s for application-wide use by core.async in lieu of its defaults. The property value should name a fully qualified var. The function will be passed workflow type keywords `:io`, `:mixed`, `:compute`, or `:core-async-dispatch`, and should return either an ExecutorService, or nil to signal to core.async to use its default. Results per keyword will be cached and used for the remainder of the application.
29+
30+
### Targeting or avoiding virtual threads
31+
32+
Users can also set the Java system property `clojure.core.async.vthreads` to control how core.async uses JDK 21+ virtual threads. The property can be one of the following values:
33+
34+
- unset - Always default to IOC when AOT compiling, and use virtual threads for `io-thread` blocks if available at runtime
35+
- `"target"` - Always target virtual threads when compiling `go` blocks and require them at runtime in `io-thread` blocks
36+
- `"avoid"` - Always use IOC when compiling `go` blocks (will work regardless), and do not use virtual threads for `io-thread` blocks
37+

0 commit comments

Comments
 (0)