Arty
Single-threaded, thread-aware runtime for async applications.
Each async task stays on one worker thread for its entire life, even when
Arty manages multiple workers. Tasks can keep thread-local and non-Send
state across awaits.
Arty can pass values between workers without moving running tasks.
The ThreadAware trait lets a value update its state
for the worker that receives it. This update is called relocation.
Quickstart
Add Arty with its default runtime and macro features:
use ;
async
This prints 42. main starts and stops the runtime.
The ? returns a JoinError if the child task fails.
Await child tasks before returning. Shutdown cancels pending async tasks.
Execution model
Each worker is one operating-system thread with a cooperative executor. The worker thread polls the tasks assigned to it. When one task awaits an operation that is not ready, the worker can poll another assigned task. After a task starts, it stays on that worker thread for its entire life.
Choose the initial worker for a new task:
Scheduler::spawnuses the worker bound to the scheduler. A cloned scheduler keeps the same binding, even when another thread calls it.Scheduler::spawn_anywherelets the runtime select a worker. This initial placement is similar to Tokio task placement.Scheduler::spawn_atuses a worker that you select from the same runtime.
Unlike a Tokio task, an Arty task does not move between workers after it starts.
A task factory creates the task future on its destination worker. A payload
is a separate value passed to that factory. If the factory starts, Arty
relocates a ThreadAware payload before the factory
uses it. Rejected tasks and tasks cancelled before their factory starts can
drop the payload without relocation.
Cloned values can refer to the same resource while keeping separate state
on each worker. ThreadAware updates that state, but it does not share
ownership of a resource or store local state for you.
This example compares fixed placement with runtime-selected placement:
let parent_worker = cx.thread.id;
let child_worker = cx
.scheduler
.spawn
.await?;
assert_eq!;
// `cx.clone()` is the payload. The closure is the task factory.
cx.scheduler
.spawn_anywhere
.await?;
spawn_anywhere can select the original worker. The relocated context
always reports the worker that runs the new task.
Each runtime owns its workers and services. Arty does not use a single runtime shared by the whole process. Each worker tracks its own state.
Arty runs tasks, provides clocks, and runs blocking functions on separate threads.
It can also run I/O drivers, which handle input and output.
I/O libraries connect to Arty through arty_io_core.
Related I/O crates ship alongside Arty.
API overview
runtimeexplains how to create, configure, and stop a runtime.taskexplains how to start tasks, choose their workers, and receive results.timeprovides clocks, delays, timeouts, and control over time in tests.ioconnects I/O libraries to the runtime.coredescribes workers and how values update their state for a worker.mainandteststart and stop a runtime for an async function or test.
Features
The default feature set enables rt, macros, and monitor.
rt: Enables the runtime, task, and I/O APIs.macros: Enablesmainandtest. It also enablesrt.monitor: Enables the Seismograph monitor dependency. It forwards monitoring support forperformableswhenperformablesis enabled. It does not start monitoring or emit new telemetry.test-util: Enables testing utilities, includingClockControl. Enable it in dev-dependencies, not production dependencies.