HackerReposA FIELD GUIDE TO OPEN SOURCE
ProSponsor the shelf♧ 0
← Back to top all-time
Tygs
ayo
Python2018–2020
Tygs / ayo · Archived

ayo

High level API for asyncio that integrates well with non ayo code

3Distinct people
8Mentions
0Explicit recommenders
30GitHub stars
REPOSITORY AT A GLANCE

What to know before exploring

What it is

High level API for asyncio that integrates well with non ayo code

GitHub

Where it is used

No documented product use has been verified yet.

What people are saying

No recommendation phrase was found in the indexed comments.

No classified warning is attached to this page. Read the discussions before treating silence as approval.

Also in these discussions

No other repository is repeatedly linked in the same discussions.

This week on Hacker News

Nov 7–Nov 14 UTC · Direct repository links and separately labeled related project stories. Indexed through 11/14/2026, 3:56:07 PM UTC.

No direct repository links were found in the indexed HN discussions over the past seven days. Older discussions are available below.

Mentions over time

HN mentions by month8 dated mentions

Observed mentions: 2018-07-15 20:31:32 UTC to 2020-05-25 00:49:14 UTC.

0122018-07-01 00:00:00 UTC to 2018-08-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 commentsJul 20182018-08-01 00:00:00 UTC to 2018-09-01 00:00:00 UTC (exclusive): 2 mentions; 0 submissions, 2 comments2018-09-01 00:00:00 UTC to 2018-10-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2018-10-01 00:00:00 UTC to 2018-11-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2018-11-01 00:00:00 UTC to 2018-12-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2018-12-01 00:00:00 UTC to 2019-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-01-01 00:00:00 UTC to 2019-02-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2019-02-01 00:00:00 UTC to 2019-03-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2019-03-01 00:00:00 UTC to 2019-04-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-04-01 00:00:00 UTC to 2019-05-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-05-01 00:00:00 UTC to 2019-06-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-06-01 00:00:00 UTC to 2019-07-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 commentsJun 20192019-07-01 00:00:00 UTC to 2019-08-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2019-08-01 00:00:00 UTC to 2019-09-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-09-01 00:00:00 UTC to 2019-10-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-10-01 00:00:00 UTC to 2019-11-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-11-01 00:00:00 UTC to 2019-12-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2019-12-01 00:00:00 UTC to 2020-01-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-01-01 00:00:00 UTC to 2020-02-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-02-01 00:00:00 UTC to 2020-03-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-03-01 00:00:00 UTC to 2020-04-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 comments2020-04-01 00:00:00 UTC to 2020-05-01 00:00:00 UTC (exclusive): 0 mentions; 0 submissions, 0 comments2020-05-01 00:00:00 UTC to 2020-06-01 00:00:00 UTC (exclusive): 1 mentions; 0 submissions, 1 commentsMay 2020

Counts come from the repository’s dated source evidence. Index cutoff: 2026-11-02 08:16:59 UTC.

View mention counts and date ranges
UTC ranges include their start and exclude their end. Select a period to filter the source evidence.
PeriodStart (UTC)End (exclusive, UTC)MentionsSubmissionsComments
Jul 20182018-07-01 00:00:00 UTC2018-08-01 00:00:00 UTC101
Aug 20182018-08-01 00:00:00 UTC2018-09-01 00:00:00 UTC202
Sep 20182018-09-01 00:00:00 UTC2018-10-01 00:00:00 UTC000
Oct 20182018-10-01 00:00:00 UTC2018-11-01 00:00:00 UTC000
Nov 20182018-11-01 00:00:00 UTC2018-12-01 00:00:00 UTC000
Dec 20182018-12-01 00:00:00 UTC2019-01-01 00:00:00 UTC000
Jan 20192019-01-01 00:00:00 UTC2019-02-01 00:00:00 UTC101
Feb 20192019-02-01 00:00:00 UTC2019-03-01 00:00:00 UTC101
Mar 20192019-03-01 00:00:00 UTC2019-04-01 00:00:00 UTC000
Apr 20192019-04-01 00:00:00 UTC2019-05-01 00:00:00 UTC000
May 20192019-05-01 00:00:00 UTC2019-06-01 00:00:00 UTC000
Jun 20192019-06-01 00:00:00 UTC2019-07-01 00:00:00 UTC000
Jul 20192019-07-01 00:00:00 UTC2019-08-01 00:00:00 UTC101
Aug 20192019-08-01 00:00:00 UTC2019-09-01 00:00:00 UTC000
Sep 20192019-09-01 00:00:00 UTC2019-10-01 00:00:00 UTC000
Oct 20192019-10-01 00:00:00 UTC2019-11-01 00:00:00 UTC000
Nov 20192019-11-01 00:00:00 UTC2019-12-01 00:00:00 UTC000
Dec 20192019-12-01 00:00:00 UTC2020-01-01 00:00:00 UTC000
Jan 20202020-01-01 00:00:00 UTC2020-02-01 00:00:00 UTC000
Feb 20202020-02-01 00:00:00 UTC2020-03-01 00:00:00 UTC000
Mar 20202020-03-01 00:00:00 UTC2020-04-01 00:00:00 UTC101
Apr 20202020-04-01 00:00:00 UTC2020-05-01 00:00:00 UTC000
May 20202020-05-01 00:00:00 UTC2020-06-01 00:00:00 UTC101

What Hacker News says

8 sources
Nathaniel has done a great job of drawing parallels between go and goto. I've been stung, time and again by asyncio.create_task() swallowing exceptions[1], and functions not telling callers about background tasks[2]. For others looking to NOT rewrite all their code using a 3rd party event loop, here's a simple reproduction of nursery's behaviour in raw asyncio - Hopefully, this will help lift the curse of asyncio :) [EDIT] A library is also available - https://github.com/Tygs/ayo (with amazing operator overload) async def main(): async with Nursery() as ny: ny.start_soon(a_1(), a_2(), ..., a_n()) ny.start_soon(b_1(), b_2(), ..., b_n()) . . . ny.start_soon(x_1(), x_2(), ..., x_n()) class Nursery: def __init__(self): self.tasks = set() def start
Read the rest
_soon(self, *coros: typing.Coroutine): for coro in coros: self.tasks.add(asyncio.create_task(coro)) async def __aenter__(self): return self async def __aexit__(self, *args): try: while self.tasks: tasks = self.tasks self.tasks = set() done, pending = await asyncio.wait( tasks, return_when=asyncio.FIRST_COMPLETED ) try: for task in done: await task finally: self.tasks |= pending finally: for task in self.tasks: task.cancel() [1] https://stackoverflow.com/questions/60287285/starlette-async... [2] https://github.com/encode/starlette/issues/947
In Guide to Concurrency in Python with Asyncio
I agree, and the docs got better too. In 3.7, asyncio is usable for people that don't understand it very well. Before that, you had to learn the whole thing brick by brick before being able to do something serious. Yet, there is a missing piece I'm hoping we'll see in 3.8: a way to limit the scope of `asyncio.ensure_future()`. Indeed, right now either you `await` to get a sequential execution , or you call `asyncio.ensure_future()` to get a concurrent one. The later, unfortunatly, is the equivalent of a GOTO, and worse, it can contain a GOTO itself (see https://vorpus.org/blog/notes-on-structured-concurrency-or-g...). So the best practice is to use `asyncio.gather()` to delimitate the pyramid of the task life cycle. Unfortunatly few people kow this, and hence do it. Plus it is not fun to do, it's boring boilerplate, something Python usua
Read the rest
lly frees you of. Yuri is thinking about how to implement the trio solution (the infamous nursery) in uvloop, and if he does, we usually get the feature ported to the stdlib a year later. Meanwhile, I noted that a simple wrapper does meet the Pareto requirement: https://github.com/Tygs/ayo/ You can see it's not really hard to write your own version of it if you need to. It helped me a lot: the code is easier to reason about, and you remove a lot of edge cases. I'll have to test Janus, it seems super nice.
In Asynchronous programming and cooperative multitasking
Trio is a better Curio, so you don't really need Curio anymore. It was what started everything and deserves credit for that though. As for Trio, it's what asyncio should have been from the beginning, at least for the high level part (although not for the pet peeves of socket programming: it's too low level for Python IMO) The problem with Trio is that it's incompatible with asyncio (minus some verbose quirky bridges), so you get yet another island, yet another ecosystem. So what, now we get twisted, tornado, gevent, qt, asyncio... and trio ? The madness must stop. And that's why I think there is a better way: creating a higher level API for asyncio, which enforces the best practices and make the common things easy, and the hard things decent. A complete rewrite like Trio would be better (e.g: it famously handles Ctrl + C way better and ha
Read the rest
s a smaller API). But this ship has sailed. We have asyncio now. asyncio is pretty good honestly. But it needs some love. So, considering asyncio is what we have to work with, and by experience, it's quite great if you know what you are doing, I advice people to actually write a wrapper around it. If you don't feel like writing a wrapper, I'll plug in the one I'm working on in case people are curious: https://github.com/Tygs/ayo It: - is based on asyncio. Not a new framework. Integrated transparently with normal asyncio. - implement some lessons leaned from trio (e.g: nurseries, cancellation, etc) - expose a sweet API (running blocking code is run.aside(callback, args, *kwargs), and automate stuff it can (@ayo.run_as_main setup the event loop and run the function in one row) - make hard things decent: timeout and concurrency limit are just a param away I does need some serious doc, including a rich tutorial which features a pure asyncio part. Also it needs some mix between streams and protocols. I'm not going to skip that part, I think it's mandatory, but I'll need many months to make the whole thing. Now, I am not Nathaniel or Yury, so my work is not nearly as bullet proof as theirs. I would not advice to install ayo in prod now, but I think it's a great proof of concept of how good asyncio can be. And we most certainly can do even better.
In The magic of asyncio explained
It's doesn't have to be complex though. It's complex because the asyncio API is terrible. It exposes loop/task factory and life cycle way to much, and shows it off in docs and tutorials. Hell, we had to wait for 3.7 to get asyncio.run() ! Even the bridge with threads, which is a fantastic feature, has a weird API: await = asyncio.get_event_loop().run_in_executor(None, callback) Also, tutorials and docs give terrible advices. They tell you to run_forever() instead of run_until_complete() and forget about telling you to activate debug mode. They also completly ignore the most important function of all: asyncio.gather(). asyncio can become a great thing, all the foundational concepts are good. In it's current form, though, it's terrible. What we need is a better API and better doc. A lot of people are currently understanding this and tr
Read the rest
ying to fix it. Nathaniel J. Smith is creating trio, a much simpler, saner alternative to asyncio: https://github.com/python-trio/trio Yury Selivanov is fixing the stdlib, and experiments with better concepts on uvloop first to integrated them later. E.G: Python 3.8 should have trio's nurseries integrated in stdlib. Personally, I don't want to wait for 3.8, and I certainly don't want the ecosystem to be fragmented between asyncio, trio or even curio. We already had the problem with twisted, tornado and gevent before. So I'm working on syntaxic sugar on top of asyncio: https://github.com/Tygs/ayo The goal is to make the API clean, easy to use, and that enforced the best practices, but stay 100% compatible with asyncio (it uses it everywhere) and it's ecosystem so that we don't get yet-another-island. It's very much a work in progress, but I think it demonstrate the main idea: asyncio is pretty good already, it just needs a little love.
In The magic of asyncio explained
Be careful with this. I'm not saying you should not do it, but consider you'll have to design it very carefully. In python you can chose what event loop to hook to async/await, and hence we have gevent, qt, uvloop, twisted, asyncio, tornado, trio and curio as competing implementations. They are very difficult to mix, and their ecosystems are mostly isolated, dividing the man power to add features, fix bugs, provide support, create libs or frameworks and write docs or tutorials. Another problem is that you have (except for gevent which causes other problems by monkey patching the stdlib) to setup the event loop explicitly. Those mechanisms are complicated, easy to get wrong, confuse beginners, make docs introduction long and annoying or misleading before getting to anything interesting. E.G: to use asyncio, you are exposed to an event loop
Read the rest
, an event loop policy, awaitable, coroutines, coroutine functions, futures, tasks and task factories. But there is worse... You can setup any event loop any way and time you want, and because the api is public, another lib can come and swap it. No lib to my knowledge provide any form of locking. This leads to some weird situation where libs are considered so low level you end up writing wrappers on top of it (e.g: https://github.com/Tygs/ayo) just to be able to start using it sanely. Now compare with JS. I'm really not a fan of the language. However, even when you can't use async/await, using a promise is straightforward. You don't have to bother about creating the loop, starting it, stopping it, cleaning after it has stopped. You don't have to wonder if somebody is going to swap the loop. You don't have to get a reference to a loop to schedule anything. Actually you can mostly ignore the loop and just code the solution to your problem. Now this makes JS dependent on one loop implementation for each runtime. Also you can't code any new async feature in JS, only use the existing ones. It's probably not what you want for a language like rust. However, you should learn from the python ecosystem fragmentation and overly exposed low level API to avoid the same mistakes. Somebody that just wants to use async/await should not have to learn how the implementation works in details, nor take so much precaution to avoid implementation lock in or break somebody else work. And you really want a federated ecosystem. Having 7 incompatible websocket lib sucks.
In Async and Await in Rust: a full proposal

MAKE YOURSELF AT HOME

A few shortcuts

/
Search the collection
?
Open this guide
Esc
Close dialogs and navigation

Your saved repositories and interests stay in this browser.