# What's the use case for io.async?

**URL:** <https://ziggit.dev/t/whats-the-use-case-for-io-async/12439>\
**Category:** Brainstorming\
**Tags:** standard-library\
**Created:** [October 10, 2025, 4:21pm UTC](https://ziggit.dev/t/whats-the-use-case-for-io-async/12439 "2025-10-10T16:21:39Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![lalinsky](https://ziggit.dev/user_avatar/ziggit.dev/lalinsky/32/3720_2.png) [@lalinsky](https://ziggit.dev/u/lalinsky)\
**Post date:** [October 10, 2025, 4:21pm UTC](https://ziggit.dev/t/whats-the-use-case-for-io-async/12439/1 "2025-10-10T16:21:39Z")

</div>

I’d really like to align zio with the future std Io, but I have a problem with the terminology.

There is `io.async` and then there is `io.concurrent`, both might spawn the function in some kind of background worker, but `io.async` might not. I understand the rationale, you want to support single-threaded blocking backend where `io.async` is a direct function call. However, when would you actually want to use `io.async`? If you are fine with the code executing serially, why would you not just call it as a function? I can’t imagine a single use case for that.

I’d much prefer if we have `io.spawn` that explicitly runs the code in some kind of background executor. You could see that as gevent in Python, where without gevent, spawn would run in a thread, with gevent, it would run in a coroutine.

There is also the need for `io.spawnBlocking`, for functions that are not cooperative, but that could be a backend-specific extension.

However, my main question is, what’s one good use case for `io.async`?

---

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [October 10, 2025, 6:37pm UTC](https://ziggit.dev/t/whats-the-use-case-for-io-async/12439/2 "2025-10-10T18:37:49Z")

</div>

> [@lalinsky](#):
>
> However, when would you actually want to use `io.async`? If you are fine with the code executing serially, why would you not just call it as a function?

If the program runs in single-threaded blocking mode async is forced to just call the function, however otherwise you still want to run the asynchronous code asyncronously. (not everyone wants to run their program in blocking mode and the code shouldn’t need to be changed to run it in non-blocking mode)

If you always just use function calls (and this code is part of a library) then the user doesn’t have the option to run it asynchronous.

> [@lalinsky](#):
>
> I’d much prefer if we have `io.spawn` that explicitly runs the code in some kind of background executor.

`io.async` allows that, but if there is no possibility to have a background executor, you can still run the code in single threaded blocking mode, which is slower but enables more use cases. Giving more options to the user.

> [@lalinsky](#):
>
> However, my main question is, what’s one good use case for `io.async`?

`io.async` enables implementation agnostic expression of the actual asyncrony and concurrency (via io.asyncConcurrent), allowing users to write the code once and use it with multiple different io implementations.

> [@Asynchrony is not Concurrency](https://ziggit.dev/t/asynchrony-is-not-concurrency/11049):
>
> This is a follow up post about async I/O in Zig that talks about these concepts in a more general manner. Hopefully this will clarify some of the ideas behind the new design that I feel were not fully grasped by a lot of people from the previous post.

---

<div class="post-metadata">

**Author:** ![kristoff](https://ziggit.dev/user_avatar/ziggit.dev/kristoff/32/9_2.png) [@kristoff](https://ziggit.dev/u/kristoff)\
**Post date:** [October 10, 2025, 7:00pm UTC](https://ziggit.dev/t/whats-the-use-case-for-io-async/12439/3 "2025-10-10T19:00:33Z")

</div>

> [@lalinsky](#):
>
> I’d much prefer if we have `io.spawn` that explicitly runs the code in some kind of background executor.

That’s `io.concurrent`.

> [@lalinsky](#):
>
> However, when would you actually want to use `io.async`?

When it would be nice to run a function in a concurrent task, but it’s not necessary for correctness. Note also that `io.async` cannot fail, while `io.concurrent` can, and you’ll have to handle the failure.

---

<div class="post-metadata">

**Author:** ![lalinsky](https://ziggit.dev/user_avatar/ziggit.dev/lalinsky/32/3720_2.png) [@lalinsky](https://ziggit.dev/u/lalinsky)\
**Post date:** [October 10, 2025, 9:19pm UTC](https://ziggit.dev/t/whats-the-use-case-for-io-async/12439/4 "2025-10-10T21:19:39Z")

</div>

I know about the difference, but do you see some use case for io.async?

---

<div class="post-metadata">

**Author:** ![vulpesx](https://ziggit.dev/user_avatar/ziggit.dev/vulpesx/32/3989_2.png) [@vulpesx](https://ziggit.dev/u/vulpesx)\
**Post date:** [October 10, 2025, 10:53pm UTC](https://ziggit.dev/t/whats-the-use-case-for-io-async/12439/5 "2025-10-10T22:53:02Z")

</div>

Let’s say I have a library that handles a _lot_ of data, and multiple streams too. It has a higher level API for the most common use case, which is where I will focus, as an example of async _ **in** _ the library.  
It’s perfectly fine to process streams one at a time, but it would be a lot faster to do them concurrently.

`io.async` expresses exactly that, it allows the caller to choose, via the Io implementation, if the processing is concurrent or not, and even the model of concurrency used.

---

<div class="post-metadata">

**Author:** ![andrewrk](https://ziggit.dev/user_avatar/ziggit.dev/andrewrk/32/7011_2.png) [@andrewrk](https://ziggit.dev/u/andrewrk)\
**Post date:** [October 11, 2025, 4:02am UTC](https://ziggit.dev/t/whats-the-use-case-for-io-async/12439/6 "2025-10-11T04:02:30Z")

</div>

- Sending/receiving/parsing multiple DNS queries in parallel
- Parsing `/etc/resolv.conf` and `/etc/hosts` at the same time
- Hashing N different files independently, before hashing the hashes together to compute package hash
- Parsing N different .zig files into ZIR independently
- Compiling N different function’s high level IR into machine code
- Scanning music files for loudness detection and calculating Acoustid
- Fetching MusicBrainz data and cover art query simultaneously

In all of these cases, there are tasks that _can_ be done serially but benefit from being done concurrently.

---

<div class="post-metadata">

**Author:** ![tsdtas](https://ziggit.dev/user_avatar/ziggit.dev/tsdtas/32/3512_2.png) [@tsdtas](https://ziggit.dev/u/tsdtas)\
**Post date:** [October 15, 2025, 10:15am UTC](https://ziggit.dev/t/whats-the-use-case-for-io-async/12439/7 "2025-10-15T10:15:36Z")

</div>

Is it a correct mental model to have that `io.async` means something _can_ happen concurrently and `io.concurrent` means that it _must_ happen concurrently?

---

<div class="post-metadata">

**Author:** ![vulpesx](https://ziggit.dev/user_avatar/ziggit.dev/vulpesx/32/3989_2.png) [@vulpesx](https://ziggit.dev/u/vulpesx)\
**Post date:** [October 15, 2025, 10:37am UTC](https://ziggit.dev/t/whats-the-use-case-for-io-async/12439/8 "2025-10-15T10:37:00Z")

</div>

That is an accurate mental model

---

<div class="post-metadata">

**Author:** ![kristoff](https://ziggit.dev/user_avatar/ziggit.dev/kristoff/32/9_2.png) [@kristoff](https://ziggit.dev/u/kristoff)\
**Post date:** [October 15, 2025, 1:31pm UTC](https://ziggit.dev/t/whats-the-use-case-for-io-async/12439/9 "2025-10-15T13:31:43Z")

</div>

Even better, it’s a factually true statement.

`io.async` can decide to allocate a unit of concurrency (thread, green thread, coroutine) to run the provided function concurrently or just call the function immediately (e.g. if resource limits were hit).

`io.concurrent` instead has to guarantee that the provided function will be placed in a different thread / green thread / coroutine.

`io.async` can be implemented basically as `return io.concurrent(f, args) catch f(args);` (slightly simplified)
