core.async and Virtual Threads
core.async 1.9.829-alpha2 is now available, which adds support for Java virtual threads ( ASYNC-262 ). Threads must block while waiting on I/O operations to complete. "Parking" allows the platform to unmount and free the underlying thread resource while waiting. This allows users to write "normal" straight line code (without callbacks) while consuming fewer platform resources. Clojure core.async go blocks until now used an analyzer to rewrite code with inversion of control specifically for channel parking operations (the ! async ops like >! ). Other blocking operations ( !! channel ops or arbitrary I/O ops) are not allowed. Since Java 21, virtual threads implement I/O parking in the Java platform itself - that capability is a superset of what go blocks provide by supporting all blocking I/O operations. Because virtual threads are a superset of go block capabilities, go blocks can now be reimplemented using virtual threads without changing their semantics. Using virtual threads This release reimplements go blocks using virtual threads when available (Java 21+). go blocks retain their existing semantics (! channel ops park, blocking I/O not allowed) but do not require loading or running the analyzer. core.async is faster to load (when using Clojure >= 1.12.3) and faster to compile go blocks (no IOC). No code or configuration changes are required. io-thread io-thread was added in a previous core.async release and is a new execution context for running both channel operations (parking or blocking) and blocking I/O operations (which are not supported in go). Since alpha2, io-thread blocks

core.async 1.9.829-alpha2 has been released, introducing support for Java virtual threads (ASYNC-262). This update enhances the way Clojure handles concurrency, particularly for I/O operations, by leveraging the platform's capabilities to optimize resource usage.
Traditionally, threads must block while waiting for I/O operations to complete. This blocking can lead to resource inefficiency, as the underlying thread remains active even when it's not performing any work. To address this, the concept of "parking" has been introduced. Parking allows the platform to unmount and free the underlying thread resource while waiting for I/O operations to finish. This feature enables users to write straightforward, linear code without callbacks, reducing the platform's resource consumption.
Prior to this release, Clojure's core.async go blocks utilized an analyzer to rewrite code with inversion of control (IOC) specifically for channel parking operations, such as the `!` async ops like `>!`. However, other blocking operations, such as `!!` channel ops or arbitrary I/O operations, were not supported. With Java 21, virtual threads now implement I/O parking natively, offering a more comprehensive solution than what go blocks provided. Virtual threads support all blocking I/O operations, making them a superset of go block capabilities.
Given that virtual threads are a superset of go block capabilities, go blocks can now be reimplemented using virtual threads without altering their semantics. The latest core.async release reimplements go blocks using virtual threads when available (Java 21+). This change retains the existing semantics of go blocks, where `!` channel ops park and blocking I/O operations are not allowed. Crucially, this update eliminates the need for loading or running the analyzer, resulting in faster loading times for core.async (when using Clojure ≥ 1.12.3) and faster compilation of go blocks (no IOC). Importantly, no code or configuration changes are required for users to benefit from this improvement.
In addition to the go block enhancements, core.async has introduced `io-thread`, a new execution context for running both channel operations (parking or blocking) and blocking I/O operations, which were not supported in go blocks. Since the alpha2 release, `io-thread` also runs in virtual threads, further optimizing performance.
To manage virtual thread usage, a new system property `clojure.core.async.vthreads` has been added. This property can take the following values:
- (unset, default): core.async will opportunistically use virtual threads when available (≥ Java 21) and will otherwise use the old analyzer implementation. `io-thread` and `:io` thread pool will run on platform threads if virtual threads are not available.
- `true`: core.async will always use virtual threads, even if they are not the default.
- `false`: core.async will never use virtual threads, falling back to the old analyzer implementation.
This release streamlines core.async's concurrency model, making it more efficient and compatible with modern Java versions. By leveraging virtual threads, developers can write cleaner, more resource-efficient code without compromising on performance. The seamless integration of virtual threads into core.async's existing architecture ensures that users can take advantage of these improvements without needing to modify their code or configurations.










