Live data from Hacker News

Async Python is not faster

calpaterson.com

101–110 of 364 posts

Re: Async Python is not faster

#101

> Function colouring is a big problem in Python Not when you know how to call sync functions from async functions and vice versa. An sync function can call an async function via: loop = asyncio.new_event_loop() result = loop.run_until_complete(asyncio.ensure_future(red(x))) A async function can call a sync function via: loop = asyncio.get_event_loop() result = await loop.run_in_executor(None, blue, x) Where red and b…

You perfectly illustrated why this is a problem. Calling functions from one side to the other involves ceremony. Ceremony adds cognitive overhead and decreases readability.

I've written Python functions that "call" another function either async or not depending on how the function inspects.

For instance, imagine a "maybe_await" method that just calls sync if is synchronous or otherwise awaits.

Re: Async Python is not faster

#102

This reminds me of Rob Pike’s talk from Golang about how concurrency is not parallelism. I think the python community may be hitting this issue where async is meant to model concurrent behavior not always or necessarily facilitate parallel activity

I think a good chunk of Python developers expected (expect?) async to be a "get out of GIL free card". It's not.

Re: Async Python is not faster

#103
post #93

How is this result surprising? The point of coroutines isn't to make your code execute faster, it's to prevent your process sitting idle while it waits for I/O. When you're dealing with external REST APIs that take multiple seconds to respond, then the async version is substantially "faster" because your process can get some other useful work done while it's waiting. Obviously the async framework introduces some over…

>it's to prevent your process sitting idle while it waits for I/O.

...with the goal of making your application faster.

Re: Async Python is not faster

#104
post #71
post #43

His async code creates a pool with only 10 max connections[1] (the default). Whereas his sync pool[2], with a flask app that has 16 workers, has significantly more database connections. I expect upping this number would have a positive effect on asyncio numbers because the only thing[3] this[4] is[5] measuring[6] is how many database connections you have, and is about as far from a realistic workload as you can get.…

> His async code creates a pool with only 10 max connections[1] (the default). Whereas his sync pool[2], with a flask app that has 16 workers, has significantly more database connections. And the reasoning is explained in the article: "The rule I used for deciding on what the optimal number of worker processes was is simple: for each framework I started at a single worker and increased the worker count successively u…

That is talking about WSGI worker processes. OP is talking about database pool connections. They are not the same thing.

Re: Async Python is not faster

#105
post #93

How is this result surprising? The point of coroutines isn't to make your code execute faster, it's to prevent your process sitting idle while it waits for I/O. When you're dealing with external REST APIs that take multiple seconds to respond, then the async version is substantially "faster" because your process can get some other useful work done while it's waiting. Obviously the async framework introduces some over…

I think it is surprising to a lot of people who do take it as read that async will be faster.

As I describe in the first line of my article I don't think that people who think async is faster have unreasonable expectations. It seems very intuitive to assume that greater concurrency would mean greater performance - at least one some measure.

> When you're dealing with external REST APIs that take multiple seconds to respond, then the async version is substantially "faster" because your process can get some other useful work done while it's waiting.

I'm afraid I also don't think you have this right conceptually. An async implementation that does multiple ("embarrassingly parallel") tasks in the same process - whether that is DB IO waiting or microservice IO waiting - is not necessarily a performance improvement over a sync version that just starts more workers and has the OS kernel scheduler organise things. In fact in practice an async version is normally lower throughput, higher latency and more fragile. This is really what I'm getting at when I say async is not faster.

Fundamentally, you do not waste "3 billion cpu cycles" waiting 1000ms for an external service. Making alternative use of the otherwise idle CPU is the purpose (and IMO the proper domain of) operating systems.

Re: Async Python is not faster

#106
post #93

How is this result surprising? The point of coroutines isn't to make your code execute faster, it's to prevent your process sitting idle while it waits for I/O. When you're dealing with external REST APIs that take multiple seconds to respond, then the async version is substantially "faster" because your process can get some other useful work done while it's waiting. Obviously the async framework introduces some over…

>it's to prevent your process sitting idle while it waits for I/O. ...with the goal of making your application faster.

... no. With the goal of allowing concurrency without parallelism.

In doing that, you're removing natural parallelism, and end up competing with the kernel scheduler, both in performance and in scheduling decisions.

Re: Async Python is not faster

#107

> Function colouring is a big problem in Python Not when you know how to call sync functions from async functions and vice versa. An sync function can call an async function via: loop = asyncio.new_event_loop() result = loop.run_until_complete(asyncio.ensure_future(red(x))) A async function can call a sync function via: loop = asyncio.get_event_loop() result = await loop.run_in_executor(None, blue, x) Where red and b…

Writing such code to call between sync/async makes me cry man - this is so ugly. I'd still consider it a problem.

Re: Async Python is not faster

#108
post #80

I find it interesting that all the talk here is about performance, and nobody has mentioned any benefits of Async Python when performance isn't an issue. I use trio/asyncio to more easily write correct complex concurrent code when performance doesn't matter. See "The Problem with Threads"[1]. For this use case, Async Python probably still isn't faster, but that doesn't matter. Let's not throw out the baby with the ba…

Whats the point of writing concurrent code if its not faster?

Re: Async Python is not faster

#109

Earlier quoted context omitted.

You perfectly illustrated why this is a problem. Calling functions from one side to the other involves ceremony. Ceremony adds cognitive overhead and decreases readability.

I've written Python functions that "call" another function either async or not depending on how the function inspects. For instance, imagine a "maybe_await" method that just calls sync if is synchronous or otherwise awaits.

It's very heavy to do this is it not? Like you inspect the function on each call to figure out if it's async or not?

Re: Async Python is not faster

#110
post #93

How is this result surprising? The point of coroutines isn't to make your code execute faster, it's to prevent your process sitting idle while it waits for I/O. When you're dealing with external REST APIs that take multiple seconds to respond, then the async version is substantially "faster" because your process can get some other useful work done while it's waiting. Obviously the async framework introduces some over…

I think it is surprising to a lot of people who do take it as read that async will be faster. As I describe in the first line of my article I don't think that people who think async is faster have unreasonable expectations. It seems very intuitive to assume that greater concurrency would mean greater performance - at least one some measure. > When you're dealing with external REST APIs that take multiple seconds to r…

>... is not necessarily a performance improvement over a sync version that just starts more workers and has the OS kernel scheduler organise things.

This is very true, especially when actual work is involved.

Remember, the kernel uses the exact same mechanism to have a process wait on a synchronous read/write, as it does for a processes issuing epoll_wait. Furthermore, isolating tasks into their own processes (or, sigh, threads), allows the kernel scheduler to make much better decisions, such as scheduling fairness and QoS to keep the system responsive under load surges.

Now, async might be more efficient if you serve extreme numbers of concurrent requests from a single thread if your request processing is so simple that the scheduling cost becomes a significant portion of the processing time.

... but if your request processing happens in Python, that's not the case. Your own scheduler implementation (your event loop) will likely also end up eating some resources (remember, you're not bypassing anything, just duplicating functionality), and is very unlikely to be as smart or as fair as that of the kernel. It's probably also entirely unable to do parallel processing.

And this is all before we get into the details of how you easily end up fighting against the scheduler...

Post reply on HN