{
    "archive_path": "archive/1789164496.093928",
    "base_url": "cel.cs.brown.edu/blog/design-space-async-await",
    "basename": "",
    "bookmarked_date": "2026-09-11 22:08",
    "canonical": {
        "archive_org_path": "https://web.archive.org/web/cel.cs.brown.edu/blog/design-space-async-await",
        "dom_path": "output.html",
        "favicon_path": "favicon.ico",
        "git_path": "git/",
        "google_favicon_path": "https://www.google.com/s2/favicons?domain=cel.cs.brown.edu",
        "headers_path": "headers.json",
        "htmltotext_path": "htmltotext.txt",
        "index_path": "index.html",
        "media_path": "media/",
        "mercury_path": "mercury/content.html",
        "pdf_path": "output.pdf",
        "readability_path": "readability/content.html",
        "screenshot_path": "screenshot.png",
        "singlefile_path": "singlefile.html",
        "warc_path": "warc/",
        "wget_path": "cel.cs.brown.edu/blog/design-space-async-await/index.html"
    },
    "domain": "cel.cs.brown.edu",
    "extension": "",
    "hash": "1D0X0K2EFCEB96R7CS3Z",
    "history": {
        "archive_org": [],
        "dom": [],
        "favicon": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--max-time",
                    "120",
                    "--output",
                    "favicon.ico",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://www.google.com/s2/favicons?domain=cel.cs.brown.edu"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-09-11T22:09:31.800016+00:00",
                "index_texts": null,
                "output": "favicon.ico",
                "pwd": "/data/archive/1789164496.093928",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-11T22:09:31.307629+00:00",
                "status": "succeeded"
            }
        ],
        "git": [],
        "headers": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--head",
                    "--max-time",
                    "120",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://cel.cs.brown.edu/blog/design-space-async-await/"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-09-11T22:09:32.146755+00:00",
                "index_texts": null,
                "output": "headers.json",
                "pwd": "/data/archive/1789164496.093928",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-11T22:09:31.807717+00:00",
                "status": "succeeded"
            }
        ],
        "htmltotext": [],
        "media": [],
        "mercury": [
            {
                "cmd": [
                    "/app/node_modules/@postlight/parser/cli.js",
                    "https://cel.cs.brown.edu/blog/design-space-async-await/"
                ],
                "cmd_version": "1.0.0",
                "end_ts": "2026-09-11T22:09:39.017310+00:00",
                "index_texts": null,
                "output": "mercury",
                "pwd": "/data/archive/1789164496.093928",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-11T22:09:35.267570+00:00",
                "status": "succeeded"
            }
        ],
        "pdf": [],
        "readability": [
            {
                "cmd": [
                    "/app/node_modules/readability-extractor/readability-extractor",
                    "/tmp/tmpu0uz_jpf",
                    "https://cel.cs.brown.edu/blog/design-space-async-await/"
                ],
                "cmd_version": "0.0.11",
                "end_ts": "2026-09-11T22:09:35.258285+00:00",
                "index_texts": [
                    "Many programming languages now provide the async/await keywords for expressing concurrency. The design rationale is pretty consistent: to make concurrent programs look more like straight-line code (see: Python, Rust, or Swift). We therefore describe the paradigm which encompasses async/await as straight-line asynchrony, as opposed to using event loops or callbacks.Language designs for straight-line asynchrony have been brewing for over 15 years. In this project, we wanted to understand: how similar or different is async/await between languages? The short answer is a lot more different than we expected. We wrote a paper, \u201cA Design Space Exploration of Async/Await\u201d, to explain how.So you think you know async/await?To demonstrate how much modern languages can diverge, here\u2019s a small async program written in pseudocode. One function writes to a log, and another fires off the log write as a background task and moves on.async fn write_to_log():\n  print(\"A\")\n  // simulate a slow log write\n  await sleep(2)\n  print(\"B\")\n\nasync fn fire_and_forget():\n  task = spawn write_to_log()\n  // return without awaiting the task\n\nasync fn main():\n  await fire_and_forget()\n  await sleep(1)\n  print(\"C\")What would you expect this program to print?There isn\u2019t really a right answer, because you were probably right for some language. Below is how seven modern async runtimes actually behave:Four different answers, for a program whose entire job is to write a log line in the background. And it gets worse. In the paper, we show that across the seven runtimes, no two produce the same output for three variations of this simple program!Do you actually know your language\u2019s async semantics?Why the disagreement?While watching videos from a programming influencer you may have have heard the terms \u201ccold\u201d or \u201chot\u201d async function calls. The idea is that \u201chot starts\u201d return a task that is immediately running in the runtime, while \u201ccold starts\u201d return an inert object that does nothing until awaited.Hot vs. cold functions is what we call an async design dimension: a design decision that affects the observable semantics of program execution (as opposed to matters of pure performance). We call this particular dimension \u201cEagerness\u201d, and in the paper we identify nine such dimensions from modern implementations of straight-line asynchrony. Below we\u2019ve grouped these nine dimension into three categories that roughly correspond to the lifetime of a task: Start of Life, End of Life, and Cancellation.Click a language to trace its design choices through the table.Start of LifeEagernessHow to evaluate an async function application.LazyEvaluate to a coroutine without executing further. \u00b7 EagerEvaluate in current thread, and schedule as task on await. \u00b7 SuspensionGuarantees on whether await points suspend.StaticAwait points guaranteed to suspend.DynamicNo guarantees on awaiting tasks. \u00b7  \u00b7  \u00b7  \u00b7  \u00b7 End of LifeExtentThe default interval of time during which a task may exist.IndefiniteTasks by default may exist until the end of the runtime. \u00b7  \u00b7  \u00b7  \u00b7 DynamicTasks by default may exist until the end of their spawning scope. \u00b7 Reference Strength[For Indefinite Extent] The type of reference to a task held by the runtime.StrongThe runtime holds a strong reference. \u00b7  \u00b7 WeakThe runtime holds a weak reference. \u00b7 DestructionHow a task is cleaned up at the end of its extent.AwaitedThe task is awaited to completion. \u00b7 CancelledThe task is cancelled, and then possibly awaited. \u00b7  \u00b7  \u00b7 TerminatedThe program exits.PropagationWhat happens to exceptions in unawaited tasks.DestructiveExceptions are reraised by dependents.NeverThe exception is kept within the task. \u00b7  \u00b7  \u00b7  \u00b7  \u00b7 CancellationAwarenessWhether a task is able to respond to being cancelled.UnawareThe task cannot respond to being cancelled.AwareThe task can respond to being cancelled. \u00b7  \u00b7 DirectionHow cancellation is communicated through the task graph.Top-DownStarting from the root task, and communicated from dependents to dependencies.Bottom-UpStarting from the root\u2019s dependencies and communicated to dependents. \u00b7 SimultaneousTo all transitive dependencies at once.Persistence[For Aware Cancellation] How long a cancellation of a task lasts.TransientA task can ignore cancellation and proceed as normal.PersistentA task can ignore cancellation but remains cancelled. \u00b7 Two of these axes are particularly relevant for our example program. Languages with Dynamic Extent do not allow tasks to outlive the functions in which they were spawned. Unlike the other languages, Swift and Python+Trio chose Dynamic Extent. This means that within the function fire_and_forget, the task associated with write_to_log cannot outlive the function fire_and_forget.Although Swift and Trio both chose Dynamic Extent, they differ in choice of Destruction. At the end of the fire_and_forget function scope, Swift uses Cancelled Destruction, and cancels task while Trio uses Awaited Destruction and politely waits for write_to_log to finish. The choices of Extent and Destruction explain why Swift prints \u201cAC\u201d and Trio prints \u201cABC\u201d.Each design dimension has trade-offs of performance, memory usage, ergonomics, semantics, etc. There\u2019s no right or wrong answers, and each language has its own design rationale. But with so many decisions, explaining the output for even small programs becomes quite involved!To make our design space more precise, we translated it into a formal semantics on a core calculus of asynchronous programs. This model lets us explain exactly why the sample program diverges by tracing its execution.The figure below provides a glimpse of how this formal model can be used to explain different execution outcomes. The figure shows the trace of the model, highlighting the semantic decisions that lead to different outcomes. Each box is an abstract-machine state. Each arrow is a small-step reduction, labeled with the rules that fire. Most rules behave identically in every runtime; the highlighted ones are the design decisions, and each highlight is a fork in the road.async fn write_to_log():  print \u201cA\u201d; await sleep(2); print \u201cB\"async fn fire_and_forget():  task = spawn write_to_log()async fn main():  await fire_and_forget();  await sleep(1); print \u201cC\"block_on(main())out: \u03b5acjkmrsC[ spawn write_to_log() ]out: \u03b5acjkmrsC[ task ]T: (2, write_to_log, print \u201cB\u201d)out: AcjC[ task;   cancel task;   try     await task   catch e -> ()]Q: print \u201cA\u201d; await sleep(2); print \u201cB\"out: \u03b5sC[ spawn coro ]out: \u03b5akmrC[ task ]Q: print \u201cA\u201d; await sleep(2); print \u201cB\"out: \u03b5akmC[ task; await task ]Q: print \u201cA\u201d; await sleep(2); print \u201cB\"out: \u03b5rblock_on(())T: (2, write_to_log, print \u201cB\u201d)out: ACacjkC[ throw \u201ccancelled\u201d ]out: As(); await sleep(1); print \u201cC\"out: As(); await sleep(1); print \u201cC\"out: \u03b5m(); await sleep(1); print \u201cC\"out: ABrBlock-WaitAsync-AppAwaitAsync-AppeagerOS-IOAsync-Appsemi-eagerAsync-ApplazySpawndynamicSpawnindefiniteOS-IOSignalScheduleScheduleOS-IOSignalCancel-UnstartedOS-IOSignalScheduleBlock-DoneScheduleOS-IOSignalAwait-TaskOS-IOSignalScheduleBlock-DoneScheduleOS-IOAwaitCatch-ExnOS-IOSignalScheduleBlock-DoneBlock-DoneterminatedSignalScheduleBlock-Doneawaitedlanguagesa = Asyncioc = C#j = JavaScriptk = Tokiom = Smolr = Trios = SwiftTo understand this diagram, and the decisions that went into designing your favorite language\u2019s async/await system, read our new paper \u201cA Design Space Exploration of Async/Await\u201d!"
                ],
                "output": "readability",
                "pwd": "/data/archive/1789164496.093928",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-11T22:09:33.528424+00:00",
                "status": "succeeded"
            }
        ],
        "screenshot": [],
        "singlefile": [],
        "title": [
            {
                "cmd": [
                    "curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--max-time",
                    "120",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) curl/curl 8.14.1 (x86_64-pc-linux-gnu)",
                    "https://cel.cs.brown.edu/blog/design-space-async-await/"
                ],
                "cmd_version": "curl 8.14.1 (x86_64-pc-linux-gnu)",
                "end_ts": "2026-09-11T22:09:33.520123+00:00",
                "index_texts": null,
                "output": "A Design Space Exploration of Async/Await",
                "pwd": "/data/archive/1789164496.093928",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-11T22:09:33.502600+00:00",
                "status": "succeeded"
            }
        ],
        "wget": [
            {
                "cmd": [
                    "wget",
                    "--no-verbose",
                    "--adjust-extension",
                    "--convert-links",
                    "--force-directories",
                    "--backup-converted",
                    "--span-hosts",
                    "--no-parent",
                    "-e",
                    "robots=off",
                    "--timeout=120",
                    "--restrict-file-names=windows",
                    "--warc-file=/data/archive/1789164496.093928/warc/1789164572",
                    "--page-requisites",
                    "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 ArchiveBox/0.7.4 (+https://github.com/ArchiveBox/ArchiveBox/) wget/GNU Wget 1.21.3",
                    "--compression=auto",
                    "https://cel.cs.brown.edu/blog/design-space-async-await/"
                ],
                "cmd_version": "GNU Wget 1.21.3",
                "end_ts": "2026-09-11T22:09:33.489239+00:00",
                "index_texts": null,
                "output": "cel.cs.brown.edu/blog/design-space-async-await/index.html",
                "pwd": "/data/archive/1789164496.093928",
                "schema": "ArchiveResult",
                "start_ts": "2026-09-11T22:09:32.155692+00:00",
                "status": "succeeded"
            }
        ]
    },
    "icons": null,
    "is_archived": true,
    "is_static": false,
    "latest": {
        "archive_org": null,
        "dom": null,
        "favicon": "favicon.ico",
        "git": null,
        "media": null,
        "pdf": null,
        "screenshot": null,
        "singlefile": null,
        "title": "A Design Space Exploration of Async/Await",
        "warc": null,
        "wget": "cel.cs.brown.edu/blog/design-space-async-await/index.html"
    },
    "link_dir": "/data/archive/1789164496.093928",
    "newest_archive_date": "2026-09-11T22:09:35.267570+00:00",
    "num_failures": 0,
    "num_outputs": 6,
    "oldest_archive_date": "2026-09-11T22:09:31.307629+00:00",
    "path": "/blog/design-space-async-await/",
    "schema": "Link",
    "scheme": "https",
    "snapshot_id": "881e07ef-e96f-4a21-8fdf-a9d47a7a27af",
    "sources": [
        "/data/sources/1789164496-import.txt"
    ],
    "tags": null,
    "tags_str": "",
    "timestamp": "1789164496.093928",
    "title": "A Design Space Exploration of Async/Await",
    "updated": "2026-09-11T22:09:31.307186+00:00",
    "updated_date": "2026-09-11 22:09",
    "url": "https://cel.cs.brown.edu/blog/design-space-async-await/"
}