top | item 14213540

Write Fast Apps Using Async Python 3.6 and Redis

337 points| midas | 8 years ago |eng.paxos.com

128 comments

order
[+] zzzeek|8 years ago|reply
> we make heavy use of asyncio because it’s more performant

more performant than....what exactly? If I need to load 1000 rows from a database and splash them on a webpage, will my response time go from the 300ms it takes without asyncio to something "more performant", like 50ms? Answer: no. async only gives you throughput, it has nothing to do with "faster" as far as the Python interpreter / GIL / anything like that. If you aren't actually spanning among dozens/hundreds/thousands of network connections, non-blocking IO isn't buying you much at all over using blocking IO with threads, and of course async / greenlets / threads are not a prerequisite for non-blocking IO in any case (only select() is).

it's nice that uvloop seems to be working on removing the terrible performance latency that out-of-the-box asyncio adds, so that's a reason that asyncio can really be viable as a means of gaining throughput without adding lots of latency you wouldn't get with gevent. But I can do without the enforced async boilerplate. Thanks javascript!

[+] bysin|8 years ago|reply
I'm glad you said this. There's an async cargo cult going on, where every service must be written in "performant" async code, without knowing the actual resource and load requirements of an application.

From the last benchmark I ran [1] async IO was insignificantly faster than thread-per-connection blocking IO in terms of latency, and marginally faster only after we hit a large number of clients.

Async IO doesn't necessarily make your code faster, it just makes it difficult to read.

[1] http://byteworm.com/evidence-based-research/2017/03/04/compa...

[+] tyingq|8 years ago|reply
Heh. Somebody will assemble a few of these pieces, add a package manager for async oriented libs, call it node.py, and then market it a bit.

Then you'll really be irritated.

[+] merb|8 years ago|reply
well it can also make things faster. well in your example it won't. but consider you need to load 4 requests and do operations on each of them. if you schedule them in an async fashion you can begin operating on the first one that's ready and not the first one you defined. and this is also often the case. a website does not just do one request to the database. mostly it runs multiple ones and often they don't interfere. like getting 20 rows and the count as a whole, there is just no need to start the first and wait till you have 20 rows and then start the second. you should always start both and wait till you have both.

yes it does not magically make your fetching 100 rows faster or your pbkdf2()/bcrypt() function. you still need to wait for those.

[+] ma2rten|8 years ago|reply
Will my response time go from the 300ms it takes without asyncio to something "more performant", like 50ms

If you have to do 1000 queries it could, since could async will make it feasible to do them parallel. If it's a single query, maybe async would make it feasible to shard the database.

[+] flukus|8 years ago|reply
> more performant than....what exactly? If I need to load 1000 rows from a database and splash them on a webpage, will my response time go from the 300ms it takes without asyncio to something "more performant", like 50ms?

Potentially, it depends on if you can do other tasks for the same request that don't depend on the data. You might be able to render most of the page for instance. It's not purely about throughput.

Please tell me that 300ms was made up too and that it's not really taking that long.

[+] anentropic|8 years ago|reply
If you have to make several requests to db backend to fulfil one response then potentially asyncio allows you to make them in parallel rather than in series. Reducing latency of your response.
[+] est|8 years ago|reply
> If I need to load 1000 rows from a database and splash them on a webpage, will my response time go from the 300ms it takes without asyncio to something "more performant", like 50ms? Answer: no

Well, actually, yes. Without async rendering, your webpage is not ready until your 1000 rows of list is placed in Python memory then rendered to HTML as a whole then returned to your browser after like 300ms of server cost.

With async rendering, your webpage's headers and such can be returned immediately, thus your first-byte-to-response time can be done under 50ms, and your page loads by enumerating the rest of 1000 rows and renders the page incrementally.

[+] Dowwie|8 years ago|reply
You are the hero we need, Mike
[+] erikcw|8 years ago|reply
We've just recently started using Sanic[0] paired with Redis to great effect for a very high throughput web service. It also uses Python 3 asyncio/uvloop at its core. So far very happy with it.

[0] https://github.com/channelcat/sanic

[+] Waterluvian|8 years ago|reply
I have never found a good example of a Python web server that provides some mechanism for statefulness. Is it just fundamentally not possible to have shared state among requests handled by the threads of a process? Sanic's examples seem to be the same as Flask's: self-contained function calls attached to endpoints.

I keep hitting a wall with Python when I want to do something like:

1. subscribe to a websocket connection and keep the last received message in state 2. expose an http endpoint to let a client GET that last message.

[+] vram22|8 years ago|reply
Any idea how Sanic compares with Falcon? I read somewhere recently that Falcon was quite fast. I tried out Hug, which is built on Falcon, but only for a small demo app, not done any benchmarking.
[+] fafhrd91|8 years ago|reply
problem with Sanic that it does not implement streaming properly. so it is very easy to kill any Sanic process, 10-20 seconds. again any.
[+] wiremine|8 years ago|reply
Been doing the same thing: Sanic is great!
[+] mixmastamyk|8 years ago|reply
Can anyone recommend a good book to get started on concurrency, with discussions of models, and a few implementations such as golang and python 3.5+?

While I can write this kind of code, I don't feel like I completely understand some of the concepts.

[+] dom0|8 years ago|reply
Concurrency and parallelism is such a huge landscape of difficult problems and complexity that I doubt any such introduction exists. I never found one, anyway.
[+] cies|8 years ago|reply
> Write Fast Apps Using Async Python

When working with Python and Ruby I find 80ms responses acceptable. In very optimized situations (no framework) this can do down to 20ms.

Now I've used some Haskell, OCaml and Go and I have learned that they can typically respond in <5ms. And that having a framework in place barely increases the response times.

In both cases this includes querying the db several times (db queries usually take less then a millisecond, Redis shall be quite similar to the extend that it does not change outcome).

<5ms makes it possible to not worry about caching (and thus cache invalidation) for a much longer time.

I've come to the conclusion that --considering other languages-- speed is not to be found in Python and Ruby.

Apart from the speed story there's also resource consumption, and in that game it is only compiled languages that truly compete.

Last point: give the point I make above and that nowadays "the web is the UI", I believe that languages for hi-perf application development should: compile to native and compile to JS. Candidates: OCaml/Reason (BuckleScript), Haskell (GHCJS), PureScript (ps-native), [please add if I forgot any]

[+] StreamBright|8 years ago|reply
>>> The performance of uvloop-based asyncio is close to that of Go programs.

I would prefer standard benchmarks for this. I hope they submit their framework to TechEnpower benchmarks.

https://www.techempower.com/benchmarks/

[+] pekk|8 years ago|reply
Those benchmarks aren't any more standard than anything else.
[+] njharman|8 years ago|reply
> You get the benefits of a database, with the performance of RAM!

One of the benefits of modern RDBMS is that they make extremely sophisticated use of RAM, and all levels of fast to slow storage below that SSD / RAIDs / slow single spindle.

[+] siscia|8 years ago|reply
Quite related, but if you want to use Redis as a SQL database I wrote an extension to do just that: https://github.com/RedBeardLab/rediSQL

It is a relative thin layer of rust code between the Redis module interface and SQLite.

At the moment you can simply execute statements but any suggestion and feature request is very welcome.

Yes, it is possible to do join, to use the LIKE operator and pretty much everything that SQLite gives you.

It is a multi-thread module, which means that it does NOT block the main redis thread and perform quite well. On my machine I achieved 50.000 inserts per seconds for the in memory database.

If you have any question feel free to ask here or to open issues and pull request in the main repo.

:)

[+] VT_Drew|8 years ago|reply
>One of the common complaints people have about python and other popular interpreted languages (Ruby, JavaScript, PHP, Perl, etc) is that they’re slow.

Proceeds to show an animation of posting a blog post that performs no faster than if it was built using Django.

[+] NightlyDev|8 years ago|reply
> 10k pageviews took ~41s

Might be that the server is insanely slow, but I would have no problems reaching 10k page views per second with some basic PHP and even MariaDB on a low end E3-1230 server. Pretty sure more would be quite easy to...

[+] fritzy|8 years ago|reply
It seems strange that they would claim that Python's libuv based event loop is twice as fast as Node.js's libuv based event loop. There's some context missing to that statement or it's flat out false.
[+] GroSacASacs|8 years ago|reply
What does it even mean. The event loop is only used when there is nothing going on. Is it faster at doing nothing ?
[+] hasenj|8 years ago|reply
If you want performance don't use Python.
[+] theprop|8 years ago|reply
This is to get a high performance ready app out. You could probably get an app out faster in PHP or Meteor or other prototyping framework.