1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//! Choosing worker counts, blocking pools, and runtime services.
//!
//! Use [`Runtime::builder`](crate::runtime::Runtime::builder) when the defaults
//! do not fit your application. Set your options before calling
//! [`build`](crate::runtime::RuntimeBuilder::build), which starts the workers.
//!
//! # Async workers
//!
//! [`WorkersPolicy`](crate::runtime::WorkersPolicy) selects processors, with
//! one async worker per selected processor:
//!
//! | Policy | Meaning |
//! | --- | --- |
//! | `default()` | Let Arty choose; currently uses all available processors, but that policy may evolve |
//! | `all()` | Use all available processors explicitly |
//! | `at_most(n)` | Use no more than `n`, clamping to available processors |
//! | `exactly(n)` | Require `n`; return `runtime::Error` if fewer are available |
//!
//! The runtime rejects a count of zero when it is built.
//!
//! ```
//! use arty::runtime::{BlockingPoolPolicy, Runtime, WorkersPolicy};
//!
//! fn main() -> Result<(), ohno::AppError> {
//! let runtime = Runtime::builder()
//! .workers(WorkersPolicy::at_most(2))
//! .blocking_pool(BlockingPoolPolicy::shared().max(4))
//! .build()?;
//! assert_eq!(runtime.scheduler().block_on(async |_| 42)?, 42);
//! runtime.stop()?;
//! Ok(())
//! }
//! ```
//!
//! This requests at most two async workers and a shared pool of up to four
//! blocking threads. The pool limit does not limit the whole process.
//!
//! Async worker stacks default to 2 MiB. Use
//! [`stack_size`](crate::runtime::RuntimeBuilder::stack_size) to change them;
//! a larger `RUST_MIN_STACK` takes precedence. Blocking-pool stacks are separate.
//!
//! # Blocking pools
//!
//! Blocking work runs off the async workers. By default, they share one pool.
//! Use [`BlockingPoolPolicy::shared`](crate::runtime::BlockingPoolPolicy::shared)
//! for one runtime-wide pool, or
//! [`per_worker`](crate::runtime::BlockingPoolPolicy::per_worker) to give each
//! worker its own pool. Chain [`max`](crate::runtime::BlockingPoolPolicy::max)
//! to set the thread limit. Per-worker pools can use more threads in total.
//! Choose based on your workload rather than assuming one policy is faster.
//!
//! Each blocking callback occupies one pool thread until it returns. Do not
//! create a cycle where a callback waits for async work that then awaits
//! another callback from the same saturated pool. Shared pools expose every
//! worker to that cycle; per-worker pools limit it to one worker's pool. Arty
//! rejects direct polling of a same-pool blocking handle, but it does not track
//! transitive dependencies through spawned async tasks.
//!
//! # Entry-point attributes
//!
//! With `macros` enabled, `#[arty::main]` and `#[arty::test]` create and stop
//! the runtime for you. By default, `main` chooses workers automatically and
//! `test` uses one worker.
//!
//! Use `workers = N` to cap the worker count. Build the runtime explicitly for
//! custom clocks, telemetry, blocking pools, stack sizes, or exact worker
//! policies.
//!
//! See [`main`](crate::main) and [`test`](crate::test) for the supported
//! signature and worker option. Build the runtime yourself if you need to
//! handle construction errors or own its shutdown.
//!
//! # Clocks and telemetry
//!
//! The default clock follows real time. Use
//! [`RuntimeBuilder::clock`](crate::runtime::RuntimeBuilder::clock) for a
//! custom clock; see [time](super::time) for controlled-time tests.
//!
//! The default telemetry sink disables events and task enrichment. Configure
//! [`RuntimeBuilder::sink`](crate::runtime::RuntimeBuilder::sink) to enable
//! them; see [telemetry](super::telemetry).
//!
//! # Async I/O
//!
//! Arty does not provide an async I/O driver. Use
//! [`spawn_blocking`](crate::task::Scheduler::spawn_blocking) for synchronous
//! I/O; libraries requiring another runtime's I/O driver still need that driver.
//!
//! # Worker placement
//!
//! A task stays on its worker once started. For
//! [`RuntimeScheduler::spawn_anywhere`](crate::task::RuntimeScheduler::spawn_anywhere)
//! and [`Scheduler::spawn_anywhere`](crate::task::Scheduler::spawn_anywhere),
//! the runtime chooses where new work starts; it does not move running tasks
//! between workers. Measure your workload before choosing worker and pool limits.