|
| 1 | +# Bring the Async Rust experience closer to parity with sync Rust |
| 2 | + |
| 3 | +| Metadata | | |
| 4 | +| -------- | ------------------------------------------------------------ | |
| 5 | +| Owner(s) | @tmandry | |
| 6 | +| Teams | [lang], [libs], [libs-api], [types] | |
| 7 | +| Status | Proposed | |
| 8 | + |
| 9 | +## Summary |
| 10 | + |
| 11 | +Over the next six months, we will continue bringing Async Rust up to par with "sync Rust" by doing the following: |
| 12 | + |
| 13 | +* Telling a complete story for the use of async fn in traits, unblocking wide ecosystem adoption, |
| 14 | +* Improving the ergonomics of `Pin`, which is frequently used in low-level async code, and |
| 15 | +* Preparing to support asynchronous (and synchronous) generators in the language. |
| 16 | + |
| 17 | +## Motivation |
| 18 | + |
| 19 | +This goal represents the next step on a multi-year program aiming to raise the experience of authoring "async Rust" to the same level of quality as "sync Rust". Async Rust is a crucial growth area, with 52% of the respondents in the [2023 Rust survey](https://blog.rust-lang.org/2024/02/19/2023-Rust-Annual-Survey-2023-results.html) indicating that they use Rust to build server-side or backend applications. |
| 20 | + |
| 21 | +### The status quo |
| 22 | + |
| 23 | +Async Rust is the most common Rust application area according to our [2023 Rust survey](https://blog.rust-lang.org/2024/02/19/2023-Rust-Annual-Survey-2023-results.html). Rust is a great fit for networked systems, especially in the extremes: |
| 24 | + |
| 25 | +* **Rust scales up**. Async Rust reduces cost for large dataplanes because a single server can serve high load without significantly increasing tail latency. |
| 26 | +* **Rust scales down.** Async Rust can be run without requiring a garbage collector or [even an operating system][embassy], making it a great fit for embedded systems. |
| 27 | +* **Rust is reliable.** Networked services run 24/7, so Rust's "if it compiles, it works" mantra means fewer unexpected failures and, in turn, fewer pages in the middle of the night. |
| 28 | + |
| 29 | +Despite async Rust's popularity, using async I/O makes Rust significantly harder to use. As one Rust user memorably put it, "Async Rust is Rust on hard mode." Several years back the async working group collected a number of ["status quo" stories](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo.html) as part of authoring an async vision doc. These stories reveal a number of characteristic challenges: |
| 30 | + |
| 31 | +* Common language features do not support async, meaning that [users cannot write Rust code in the way they are accustomed to](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/barbara_plays_with_async.html?highlight=closure#the-story): |
| 32 | + * [x] ~~[traits](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/alan_needs_async_in_traits.html)~~ (they [do now][afitblog], though gaps remain) |
| 33 | + * [x] closures (about to [stabilize](https://github.com/rust-lang/rust/pull/132706)) |
| 34 | + * [ ] [drop](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/alan_finds_database_drops_hard.html) |
| 35 | + In many cases there are workarounds or crates that can close the gap, but users have to learn about and find those crates. |
| 36 | +* Common async idioms have "sharp edges" that lead to unexpected failures, forcing users to manage [cancellation safety](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/barbara_gets_burned_by_select.html), subtle [deadlocks](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/aws_engineer/solving_a_deadlock.html) and other failure modes for [buffered streams](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/barbara_battles_buffered_streams.html). See also tmandry's blog post on [Making async Rust reliable](https://tmandry.gitlab.io/blog/posts/making-async-reliable/)). |
| 37 | +* Using async today requires users to select a runtime which provides many of the core primitives. Selecting a runtime as a user [can be stressful](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/barbara_makes_their_first_steps_into_async.html#the-wrong-time-for-big-decisions), as the [decision once made is hard to reverse](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/barbara_wishes_for_easy_runtime_switch.html). Moreover, in an attempt to avoid "picking favories", the project has not endorsed a particular runtime, making it [harder to write new user documentation](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/niklaus_wants_to_share_knowledge.html). Libraries meanwhile [cannot easily be made interoperable across runtimes](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/barbara_writes_a_runtime_agnostic_lib.html) and so are often written against the API of a particular runtime; even when libraries can be retargeted, it is difficult to do things like run their test suites to test compatibility. [Mixing and matching libraries can cause surprising failures.](https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/alan_started_trusting_the_rust_compiler_but_then_async.html) |
| 38 | + |
| 39 | +[afitblog]: https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html |
| 40 | +[embassy]: https://github.com/embassy-rs/embassy |
| 41 | +[tokio]: https://tokio.rs/ |
| 42 | + |
| 43 | +### The next 6 months |
| 44 | + |
| 45 | +#### Tell a complete story for async fn in traits |
| 46 | + |
| 47 | +* Unblock AFIT in public traits by stabilizing RTN and implementable trait aliases (unblock tower 1.0) |
| 48 | +* Ship 1.0 of the dynosaur crate, enabling dynamic dispatch with AFIT |
| 49 | +* Stretch goal: Implement experimental support for async fn in `dyn Trait` in nightly |
| 50 | + |
| 51 | +#### Improve ergonomics around `Pin` |
| 52 | + |
| 53 | +* Ratify and implement an RFC for auto-reborrowing of pinned references |
| 54 | +* Stretch goal: Ratify an RFC for safe pin projection |
| 55 | + |
| 56 | +#### Work toward asynchronous generators |
| 57 | + |
| 58 | +* Ratify an RFC for synchronous generators |
| 59 | +* Review 1-2 RFCs for asynchronous iteration trait with the lang and libs-api teams and decide on the core trait to be stabilized |
| 60 | +* Stretch goal: Ratify an RFC for unsafe binders and RTN in type position |
| 61 | + |
| 62 | +### The "shiny future" we are working towards |
| 63 | + |
| 64 | +**Writing async code in Rust should feel just as expressive, reliable, and productive as writing sync code in Rust.** Our eventual goal is to provide Rust users building on async with |
| 65 | + |
| 66 | +* the same core language capabilities as sync Rust (async traits with dyn dispatch, async closures, async drop, etc); |
| 67 | +* reliable and standardized abstractions for async control flow (streams of data, error recovery, concurrent execution), free of accidental complexity; |
| 68 | +* an easy "getting started" experience that builds on a rich ecosystem; |
| 69 | +* good performance by default, peak performance with tuning; |
| 70 | +* the ability to easily adopt custom runtimes when needed for particular environments, language interop, or specific business needs. |
| 71 | + |
| 72 | +## Design axioms |
| 73 | + |
| 74 | +* **Uphold sync Rust's bar for reliability.** Sync Rust famously delivers on the general feeling of "if it compiles, it works" -- async Rust should do the same. |
| 75 | +* **Lay the foundations for a thriving ecosystem.** The role of the Rust org is to develop the rudiments that support an interoperable and thriving async crates.io ecosystem. |
| 76 | +* **When in doubt, zero-cost is our compass.** Many of Rust's biggest users are choosing it because they know it can deliver the same performance (or better) than C. If we adopt abstractions that add overhead, we are compromising that core strength. As we build out our designs, we ensure that they don't introduce an "abstraction tax" for using them. |
| 77 | +* **From embedded to GUI to the cloud.** Async Rust covers a wide variety of use cases and we aim to make designs that can span those differing constraints with ease. |
| 78 | +* **Consistent, incremental progress.** People are building async Rust systems *today* -- we need to ship incremental improvements while also steering towards the overall outcome we want. |
| 79 | + |
| 80 | +## Ownership and team asks |
| 81 | + |
| 82 | +This section defines the specific work items that are planned and who is expected to do them. It should also include what will be needed from Rust teams. The overall owner of the effort is @tmandry. We have identified owners for subitems below; these may change over time. |
| 83 | + |
| 84 | +| Subgoal | Owner(s) or team(s) | Notes | |
| 85 | +| ---------------------------- | ---------------------------- | ------------------- | |
| 86 | +| Overall program management | @tmandry | | |
| 87 | +| ↳ AFIT story blog post | @tmandry | | |
| 88 | +| Return type notation | @nikomatsakis | | |
| 89 | +| ↳ ~~Initial implementation~~ | ~~@compiler-errors~~ | ![Complete][] | |
| 90 | +| ↳ ~~Author RFC~~ | @nikomatsakis | ![Complete][] | |
| 91 | +| ↳ ~~RFC decision~~ | ![Team][] [lang] | ![Complete][] | |
| 92 | +| ↳ Finished implementation | @compiler-errors | | |
| 93 | +| ↳ Reviews | ![Team][] [types] [compiler] | | |
| 94 | +| ↳ Stabilization decision | ![Team][] [lang] | | |
| 95 | +| Implementable trait aliases | @tmandry | | |
| 96 | +| ↳ Author RFC | @tmandry | | |
| 97 | +| ↳ Implementation | @compiler-errors | | |
| 98 | +| ↳ Reviews | ![Team][] [types] [compiler] | | |
| 99 | +| ↳ RFC decision | ![Team][] [lang] [types] | | |
| 100 | +| Pin reborrowing | @eholk | | |
| 101 | +| ↳ Implementation | @eholk | | |
| 102 | +| ↳ Author RFC | @eholk | | |
| 103 | +| ↳ RFC decision | ![Team][] [lang] | | |
| 104 | +| Trait for generators (sync) | | | |
| 105 | +| ↳ Implementation | @eholk | | |
| 106 | +| ↳ Author RFC | | | |
| 107 | +| ↳ RFC decision | ![Team][] [libs-api] [lang] | | |
| 108 | +| ↳ Design meeting | ![Team][] [lang] | 2 meetings expected | |
| 109 | +| Trait for async iteration | | | |
| 110 | +| ↳ Author RFC | | | |
| 111 | +| ↳ RFC decision | ![Team][] [libs-api] [lang] | | |
| 112 | +| ↳ Design meeting | ![Team][] [lang] | 2 meetings expected | |
| 113 | +| ↳ Implementation | | | |
| 114 | +| Dynosaur 1.0 | @spastorino | | |
| 115 | +| ↳ Implementation | @spastorino | | |
| 116 | +| ↳ Standard reviews | @tmandry | | |
| 117 | + |
| 118 | +TODO: Stretch goals |
| 119 | + |
| 120 | +### Definitions |
| 121 | + |
| 122 | +Definitions for terms used above: |
| 123 | + |
| 124 | +* *Discussion and moral support* is the lowest level offering, basically committing the team to nothing but good vibes and general support for this endeavor. |
| 125 | +* *Author RFC* and *Implementation* means actually writing the code, document, whatever. |
| 126 | +* *Design meeting* means holding a synchronous meeting to review a proposal and provide feedback (no decision expected). |
| 127 | +* *RFC decisions* means reviewing an RFC and deciding whether to accept. |
| 128 | +* *Org decisions* means reaching a decision on an organizational or policy matter. |
| 129 | +* *Secondary review* of an RFC means that the team is "tangentially" involved in the RFC and should be expected to briefly review. |
| 130 | +* *Stabilizations* means reviewing a stabilization and report and deciding whether to stabilize. |
| 131 | +* *Standard reviews* refers to reviews for PRs against the repository; these PRs are not expected to be unduly large or complicated. |
| 132 | +* *Prioritized nominations* refers to prioritized lang-team response to nominated issues, with the expectation that there will be *some* response from the next weekly triage meeting. |
| 133 | +* *Dedicated review* means identifying an individual (or group of individuals) who will review the changes, as they're expected to require significant context. |
| 134 | +* Other kinds of decisions: |
| 135 | + * [Lang team experiments](https://lang-team.rust-lang.org/how_to/experiment.html) are used to add nightly features that do not yet have an RFC. They are limited to trusted contributors and are used to resolve design details such that an RFC can be written. |
| 136 | + * Compiler [Major Change Proposal (MCP)](https://forge.rust-lang.org/compiler/mcp.html) is used to propose a 'larger than average' change and get feedback from the compiler team. |
| 137 | + * Library [API Change Proposal (ACP)](https://std-dev-guide.rust-lang.org/development/feature-lifecycle.html) describes a change to the standard library. |
| 138 | + |
| 139 | +## Frequently asked questions |
| 140 | + |
| 141 | +### Why work on synchronous generators if your goal is to support async? |
| 142 | + |
| 143 | +There are three features we want that all interact quite heavily with each other: |
| 144 | + |
| 145 | +* Sync generators |
| 146 | +* Async generators |
| 147 | +* Async iteration trait |
| 148 | + |
| 149 | +Of the three, we think we are the closest to ratifying an RFC for synchronous generators. This should help clarify one of the major outstanding questions for the other two items; namely, the relation to pinning. With that out of the way, we should better be able to focus on the iteration trait and how well it works with async generators. |
| 150 | + |
| 151 | +Focusing on pinning first also synergizes well with the efforts to improve the ergonomics of pinning. |
0 commit comments