Discussion: "Some thoughts on asynchronous API design in a post-async/await world"

#1

You can use this thread to discuss the blog post Some thoughts on asynchronous API design in a post-async/await world.

It’s long and a bit out-of-date at this point, but this is ultimately where Trio started!

#2

Being intimidated by asyncio, I’d been thinking of Curio as a self-study project. Last week I found this blog post, …and trio. Good and short name! Splendid ideas!

I don’t know if I’m wrong, but I get the impression that many more than I are intimidated by asyncio and predecessors. Trio would save them, if only they knew.
:wink:

1 Like
#3

@njs I’ve been trying to give a deeper read again at your article and it’s still a fun one. With hindsight, coming from 2019’s Trio, it’s really interesting to see how some ideas have evolved!

One thing that I haven’t fully grasped is your definition of causality. I have an intuition of it, but when I tried to explain it to others I failed miserably. It’s clear how f(); g() “respects causality”, but it’s not easy to describe when concurrent code does or does not. My intuition: if the behavior can be described as a sequence of predictably serial events then it’s “respecting causality”. But the exercise is not trivial (to me), and some complex interactions might be hard to try to explain that way. Lack of a formal method means that I fall back to intuition, which can and will be wrong.

Now, this confusion itself is to me the greatest selling point of a language/framework whose building blocks “respect causality” themselves. I would not be able to make something predictable myself as complexity grows beyond trivial, so I rely on something that is structurally more predictable. Kind of like the goto vs structured concurrency idea. But it also means that 1) I don’t have a full understanding of the concepts and 2) I won’t be able to explain how great it is to have tools that approach this problem at the root.

In order to expand my language and ability to talk about it I hoped to use this notion of “causality”, but is there some (more) formal definition to what is causal and what is not? Is there a better colloquial way to discuss it?

#4

I may have commited the sin of using a fancy word when a plain one would do :slight_smile:. All I mean is: suppose f and g are two operations with side-effects. If I write f(); g();, then f's side-effects should all happen before any of g's side-effects. Or in other words: if I write f before g, then f should happen before g :-).

It’s probably easiest to explain with examples:

  • f is “make an edit to a document”, g is “share the document with other people”. Whoops, maybe you just sent the old version of your document, with the embarrassing mistake you thought you already corrected!

  • f is “send this data”, g is “terminate the program”. Whoops, maybe the data is never sent! In fact this works with practically anything in the f slot, which is why it’s so difficult to properly shut down a program using twisted or asyncio.

  • f is “write the new version to disk”, g is “delete the old version”. Doing it in this order guarantees you won’t lose data if the system crashes, right? Well, maybe not, if your system reorders it so g happens first. (Bonus: unless your test suite simulates random power outages, the only way you will discover this bug is because it destroyed production data.)

  • f is “send data to the remote peer”, g is “generate more data to send”. If the peer stops reading, you want to stop generating new data. Twisted/asyncio protocols don’t enforce this, which is why innocent-looking Twisted/asyncio programs are so prone to memory DoS.

Zio (Scala library)