Live data from Hacker News

Python Asyncio

superfastpython.com

21–30 of 188 posts

Re: Python Asyncio

#21

After 2 years of using asyncio in production, I recommend to avoid it if you can. With async programming, you take the complexity of concurrent programming, which is way harder than you can imagine. Also nobody mentions this for some reason, but asyncio doesn't make your programs faster, in fact it makes everything 100x SLOWER (we measured it multiple times, compared the same thing to the sync version), but makes you…

This is an insane take, if you are doing async you already HAVE a need for concurrent programming. Async just makes that simpler to read and write.

> Async just makes that simpler to read and write.

Really? I definitely had a huge struggle reading async python, because generators and yields break the concept of "what is a function" and struggled writing async python because of function coloring.

Re: Python Asyncio

#22

Is this negligible in performance until the GIL radically changes? I find parallel processing has muc larger increases in speed.

Since async is single threaded the GIL shouldn't come into play.

Question though: asyncio is implemented as threads, which is where the GIL chokes, right?

Re: Python Asyncio

#23
post #17

Earlier quoted context omitted.

That's exactly the opposite of what it says really: if you need to do CPU stuff, then you can do that, it just won't be using asyncio. So it doesn't really infect your whole program. You could easily have, say, a thread to do all your asyncio stuff, another to do some CPU intenstive stuff (so long as it blocks the GIL) and yet another to do some blocking I/O e.g. interacting with a database with its own blocking APIs…

I think the issue is more like this: 1. You jump into a huge codebase and find a very useful function you want to use in your code (it uses asyncio) 2. Your code doesn't use asyncio, so you start converting functions to be async (or else you can't use the `await` keyword) 3. It turns out your function is called by a bunch of different users, some of which do not use the asyncio runner 4. You end up having several mee…

I guess I was focusing more on the CPU task problem mentioned at the top. But you're talking about blocking IO - more specifically, blocking IO that you want to convert to async (not just run in a worker thread using the thread-to-async API I mentioned).

What you've written is true, but "infects" a smaller proportion of the code than you'd expect, in my experience. In fact, the better organised the program is, the less needs to change when converting to async. For example, reading from a connection your top-level async function would often be something like this:

    async def read_and_handle_messages(connection):
        while True:
            next_message_bytes = await connection.get_next_message()
            next_message_parsed = my_parser.parse(next_message_bytes)
            my_message_handler(next_message_parsed)
All the application-specific code is in the parser and the message handler but neither of those are async. (If you need to send a response, your message handler could post a message to an async queue that is read by a separate writer task.) In your hypothetical scenario, you'd maybe write two a wrapper functions, one for blocking and one for async, which both read the message, parse it and handle it. But that only needs to be two versions of a three line function while all the subtantial code is completely shared.

I find that there's very little actual async code in async programs that I write, even with no blocking IO historical baggage. Admittedly, that's partly because I organise programs to reach that goal, but it actually works out for the best because all the async-task lifecycle management ends up in one place, which makes following overall program flow particularly easy.

Re: Python Asyncio

#24
post #2

Important to note: > They are suited to non-blocking I/O with subprocesses and sockets, however, blocking I/O and CPU-bound tasks can be used in a simulated non-blocking manner using threads and processes under the covers. If you're using it for anything besides slow async I/O, you're going to have to do some heavy lifting. I've also found the actual asyncio implementation in CPython to be slow. Measuring purely even…

Ok. This is what has been a huge hangup for me. It really seems that if you're doing asyncio, you must do EVERYTHING async, it's like asyncio takes over (infects?) the entire program.

The propagation/infection of async handling is just indicitive of the nature of the problem. Try writing async code in any other language and you see similar patterns emerge.

Re: Python Asyncio

#25

Earlier quoted context omitted.

Since async is single threaded the GIL shouldn't come into play.

Question though: asyncio is implemented as threads, which is where the GIL chokes, right?

asyncio is _not_ implemented as threads. It has features where it can wrap a sync function inside a thread in order to turn it into an async function, but if you just write "normal" async code, all your code is running in a single thread.

Re: Python Asyncio

#26

After 2 years of using asyncio in production, I recommend to avoid it if you can. With async programming, you take the complexity of concurrent programming, which is way harder than you can imagine. Also nobody mentions this for some reason, but asyncio doesn't make your programs faster, in fact it makes everything 100x SLOWER (we measured it multiple times, compared the same thing to the sync version), but makes you…

This is an insane take, if you are doing async you already HAVE a need for concurrent programming. Async just makes that simpler to read and write.

I'm pretty sure a lot of people don't understand the tradeoffs and don't really need concurrent code. There are really only a couple of use-cases where it's really handy: for example an API gateway, where you only get and send HTTP requests. Other than that, I don't see how it worth the insane complexity (compared to sync code).

You can write web servers in a sync manner; Flask, Django is way better if you only need an API, choosing FastAPI for a simple REST API is a huge mistake.

Re: Python Asyncio

#27
async is not comparable to threads: - async is concurrency - threads are parallelism

They are not exclusives, the best approach is to be multi-threaded while each of the threads uses concurrency to prevent blocking the cpu.

Re: Python Asyncio

#28

There is very little in everyday Python usage that benefits from Asyncio. Two in webdev, are long running request (Websockets, SSE, long polling), and processing multiple backend IO processes in parallel. However the later is very rare, you may think you have multiple DB request that could use asyncio, but most of the time they are dependent on each other. Almost all of the time a normal multithreaded Python server i…

Fully agree with this! Just stick to Flask/Django if you doing a simple website/API. Async also makes DB connections slower, here is a great piece from Mike Bayer from years ago: https://techspot.zzzeek.org/2015/02/15/asynchronous-python-a...

Re: Python Asyncio

#29
post #2

Important to note: > They are suited to non-blocking I/O with subprocesses and sockets, however, blocking I/O and CPU-bound tasks can be used in a simulated non-blocking manner using threads and processes under the covers. If you're using it for anything besides slow async I/O, you're going to have to do some heavy lifting. I've also found the actual asyncio implementation in CPython to be slow. Measuring purely even…

Ok. This is what has been a huge hangup for me. It really seems that if you're doing asyncio, you must do EVERYTHING async, it's like asyncio takes over (infects?) the entire program.

That's 80% due to the "what color is your function" problem.

There are bridges from async to sync and vice versa, but they must be used very sparingly, as they aren't nestable.

Re: Python Asyncio

#30

Earlier quoted context omitted.

Question though: asyncio is implemented as threads, which is where the GIL chokes, right?

asyncio is _not_ implemented as threads. It has features where it can wrap a sync function inside a thread in order to turn it into an async function, but if you just write "normal" async code, all your code is running in a single thread.

Ah, ok that makes more sense.
Post reply on HN