[HN Gopher] Async Python Is Secretly Deterministic
___________________________________________________________________
Async Python Is Secretly Deterministic
Author : KraftyOne
Score : 49 points
Date : 2026-04-03 18:55 UTC (4 hours ago)
(HTM) web link (www.dbos.dev)
(TXT) w3m dump (www.dbos.dev)
| lexicality wrote:
| > This makes it possible to write simple code that's both
| concurrent and safe.
|
| Yeah, great, my hello world program is deterministic.
|
| What happens when you introduce I/O? Is every network call
| deterministic? Can you depend on reading a file taking the same
| amount of time and being woken up by the scheduler in the same
| order every time?
| KraftyOne wrote:
| That's the cool thing about this behavior--it doesn't matter
| how complex your program is, your async functions start in the
| same order they're called (though after that, they may
| interleave and finish in any order).
| lexicality wrote:
| Only for tasks that are created in synchronous code. If you
| start two tasks that each make a web request and then start a
| new task with the result of that request you will immediately
| lose ordering.
| KraftyOne wrote:
| Yes, this only applies for tasks created from the same
| (sync or async) function. If tasks are creating other
| tasks, anything is possible.
| PufPufPuf wrote:
| This is about durable execution -- being able to resume
| execution "from the middle", which is often done by executing
| from the beginning but skipping external calls. Second time
| around, the I/O is exactly replayed from stored values, and the
| "deterministic" part only refers to the async scheduler which
| behaves the same as long as the results are the same.
|
| Coincidentally I have been experimenting with something very
| similar in JavaScript in the past and there the scheduler also
| has the same property.
| TeMPOraL wrote:
| No, but determinism reduces the number of stones you need to
| turn over when debugging hairy problems such as your program
| occasionally returning different results for the same inputs.
| You may not have control over the timing of I/O operations or
| order of external events (including OS scheduler), but at least
| you know that your side of the innovation/response is, in
| isoaltion, behaving predictably.
| arn3n wrote:
| While not production ready, I've been happily surprised at this
| functionality when building with it. I love my interpreters to be
| deterministic, or when random to be explicitly seeded. It makes
| debugging much easier when I can rerun the same program multiple
| times and expect identical results.
| frizlab wrote:
| Interestingly I think things that should not be deterministic
| should actually _forced_ not to be.
|
| Swift for instance will explicitly make iterating on a
| dictionary _not_ deterministic (by randomizing the iteration),
| in order to catch weird bugs early if a client relies
| (knowingly or not) on the specific order the elements of the
| dictionary are ordered.
| lilyball wrote:
| This claim sounds vaguely familiar to me (though the
| documentation on Dictionary does not state any reason for why
| the iteration order is unpredictable), though the more common
| reason for languages to have unstable hash table iteration
| orders is as a consequence of protection against hash
| flooding, malicious input causing all keys to hash to the
| same bucket (because iteration order is dependent on bucket
| order).
| saidinesh5 wrote:
| One more reason for randomizing hash table iteration was to
| prevent Denial of service attacks:
|
| https://lukasmartinelli.ch/web/2014/11/17/php-dos-attack-
| rev...
| 12_throw_away wrote:
| No, determinstic scheduling is not a property of async python.
|
| Yes, the stdlib asyncio event loop does have deterministic
| scheduling, but that's an implementation detail and I would not
| rely on it for anything critical. Other event loops - for
| instance trio [1] - explicitly randomize startup order so that
| you won't accidentally write code that relies on it.
|
| [1] https://github.com/python-trio/trio/issues/32
| KraftyOne wrote:
| It's been a stable (and documented) behavior of the Python
| standard library for almost a decade now. It's possible it may
| change--nothing is ever set in stone--but that would be a large
| change in Python that would come with plenty of warning and
| time for adjustment.
| 9dev wrote:
| And then one day, Astral creates a new Python implementation
| in Rust or something that is way faster and all the rage, but
| does this particular thing different than CPython. Whoops,
| you can't use that runtime, because you now have cursed parts
| in your codebase that produce nondeterministic behaviour you
| can't really find a reason for.
| ubercore wrote:
| That's a bit what it felt like when I was learning Rust
| async.
|
| I get it, but "ecosystems" of async runtimes have a pretty
| big cost.
| stuartjohnson12 wrote:
| and then all the serverless platforms will start using
| Astral's new rust-based runtime to reduce cold starts, and
| in theory it's identical, except half of packages now don't
| work and it's very hard to anticipate which ones will and
| will not and behold! You have achieved Deno
| farsa wrote:
| Well, in my early days programming python I made a lot(!!) of
| code assuming non-concurrent execution, but some of that code
| will break in the future with GIL removal. Hopefully the
| Python devs keep these important changes as opt-ins.
| StableAlkyne wrote:
| > but that's an implementation detail
|
| That sounds familiar...
|
| https://stackoverflow.com/questions/39980323/are-dictionarie...
| mort96 wrote:
| How do you differentiate between something that "happens to
| work due to an implementation detail" and a "proper feature
| that's specified to work" in a language without a
| specification?
| whinvik wrote:
| Is this guaranteed by the async specification? Or is this just
| current behavior which could be changed in a future update. Feels
| like a brittle dependency if its not part of the spec.
| KraftyOne wrote:
| It's documented behavior for the low-level API (e.g.
| asyncio.call_soon https://docs.python.org/3/library/asyncio-
| eventloop.html#asy...). More broadly, this has been a stable
| behavior of the Python standard library for almost a decade
| now. If it does change, that would be a huge behavioral change
| that would come with plenty of warning and time for adjustment.
| btilly wrote:
| In my experience, developers who rely on precise and
| relatively obscure corner cases, tend to assume that they are
| more stable than they later prove to be. I've been that
| developer, and I've been burned because of it.
|
| Even more painfully, I've been the maintenance programmer who
| was burned because some OTHER programmer trusted such a
| feature. And then it was my job to figure out the hidden
| assumption after it broke, long after the original programmer
| was gone. You know the old saying that you have to be twice
| as clever to debug code, as you need to be to write it?
| Debugging another person's clever and poorly commented tricks
| is no fun!
|
| I'd therefore trust this feature a lot less than you appear
| to. I'd be tempted to instead wrap the existing loop with a
| new loop to which I can add instrumentation etc. It's more
| work. But if it breaks, it will be clear why it broke.
| jpollock wrote:
| That's deterministic dispatch, as soon as it forks or
| communicates, it is non deterministic again?
|
| Don't you need something like a network clock to get
| deterministic replay?
|
| It can't use immediate return on replay, or else the order will
| change.
|
| This makes me twitchy. The dependencies should be better
| modelled, and idempotency used instead of logging and caching.
___________________________________________________________________
(page generated 2026-04-03 23:00 UTC)