Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'm the dev behind uvloop. AMA.


No questions, just a thank you for including relevant information about the tests content, concurrency, adding percentile boxes to graphs, etc. (and the tested environment itself!) It's refreshing to see a benchmark taken seriously rather than "we tested some stuff, here are 3 numbers, victory!".


Thanks!


1) What makes uvloop which is based on libuv 2x faster than node.js which is also based on libuv?

2) Can uvloop be used with frameworks like flask or django?

3) gevent uses monkey patching to turn blocking libraries such as DB drivers non-blocking, does uvloop do anything similar? If not how does it work with blocking libraries?


1) I don't know :( I've answered a similar question in this thread with a couple of guesses.

2) No, they have a different architecture. Although I heard that there is a project to integrate asyncio into django to get websockets and http/2.

3) asyncio/uvloop require you to use explicit async/await. So, unfortunately, the existing networking code that isn't built for asyncio can't be reused. On the bright side, there are so many asyncio DB drivers and other modules now!


> 2) No, they have a different architecture

Having a web framework (a next generation Flask if you will) built ground up with concurrency is the missing key. I have used Flask for many years, but this is the right time to introduce a new framework - because of the internal restructuring and slowdown of Flask's maintainers (and I say this with the utmost respect).

If you are keen, this has the potential to be the killer application for Python 3.


One problem with this is that the entire ecosystem has to get on board with async. Maybe a new framework would make it compelling enough, who knows.

This was/is the big issue with Tornado, IMO (and Tornado has been around for ages in framework time). Tornado is only async if the entire call stack all the way down to the http socket is async, using callbacks instead of returning values. This means that any 3rd party client library you use has to be completely written asynchronously, and none are in python. So you end up with a lot tedious work re-implementing http client libraries for Twilio or Stripe or whatever you're using.

I'm curious to see where asyncio goes in python, but I'm a bit skeptical after seeing how much of a pain it was to use Tornado on a large web app. In the meantime I'll be using Gevent + Flask, which isn't perfect since it adds some magic & complexity but has the huge upside of letting you keep using all the libraries you're used to.


There is already http://www.tornadoweb.org/en/stable/ which is python3 compatible and shipped in production software across lots of companies (last I heard hipmunk and quora uses it)


Tornado is excellent... But Flask is better than excellent. The mental map of Flask is incredible. Tornado is a little hard to grok. Now one may argue that Tornado is hard by choice...to not mask the complexity. But then we have node..the most hip of frameworks out there. Node's true innovation was not performance, but to simplify the mental model of async. Obviously there's all the callback hell and all..but still.


I'm pretty sure both Node and Tornado have the same mental model of async. Both have callbacks and both have async/await functionality that makes it look more like blocking code.

The main benefit of Node as I see it is that the entire Node community uses the same IO Loop whereas Python's community is fragmented between normal sync code and multiple different IO Loops (asyncio will probably help with this).


I'm actually thinking about writing such a framework :) I'll call it "spin".


You totally should. I think people are hungry for a next gen async web framework... And if it leverages Python 3, then so much the better. Flask cannot go here even if it wants because its core philosophy is to be WSGI compliant. You don't necessarily have to adhere to that.

Just one point, please make sure you have designed DB access as a core part of your framework (e.g. [1]). Too many frameworks discount database interaction until it's too late.

Oh and please please choose your name so that it doesn't conflict on Google search. http://www.spinframework.org

[1] http://initd.org/psycopg/docs/advanced.html#async-support vs https://github.com/chtd/psycopg2cffi


Since spin is conflicting, may I suggest spyn? Gets that nice little Python 'py' in there.


Can also be read as "spine".


> Just one point, please make sure you have designed DB access as a core part of your framework (e.g. [1]). Too many frameworks discount database interaction until it's too late.

I strongly advise against this. One of the reasons Flask is so attractive is the fact that it does not enforce any database on you.

Thanks to its decoupled design you can use it purely as a routing library, which is great! Letting the framework decide something important as the database is a bad idea. [1]

[1] https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-arc...


that is ok - but there is a representative library that works. Loosely decoupled but definitively working is beautiful... and this is why I use Flask in my startup.

what frequently happens is a web framework without a thought for any kind of DB interaction (or as you put it... a routing library). In things like an async web framework, that could leave users hanging. For example, psycopg vs psycopg2 vs psycogreen vs psycopg2-cffi . Tell me which one to use and benchmark it.

I agree, its a fine line. And we can keep going back and forth whether a framework should "recommend" or not recommend. But in case like this - I think there will NOT be a lot of libraries that will be compliant with the async usecase. I would hope that this framework will recommend... but not ship "batteries included".


If such a framework was built around asyncio, do we really need yet another database layer? 1 of the best things about Flask is it doesn't reinvent the wheel.


It's not so much as another dB layer, but some async compatible dB layer.

Most database libraries don't play very well with non blocking code. In fact nodejs dB libraries were specifically designed for this.

Building async frameworks is not trivial - http://initd.org/psycopg/docs/advanced.html#async-support


I'd like to chat with you about this, share ideas for API, and architectures. Even if we don't work to each others, we can benefit from sharing ideas about what should a next gen framework look like in Python.


Go for it! An async python web framework with the speed of Go and the ecosystem of python would be a killer app.


We are actually working on a project like this with Tygs (https://github.com/Tygs/tygs, which will use crossbar.io), and right now it's taking ages just to get the app life cycle right.

Indeed, we want to make it very easy to use, especially a clean/discoverable API, simple debugging, clear errors, etc. Which is the stuff async frameworks are not good at, and an incredible added value.

It's a lot more work we initially thought. When you are doing async, you now think, not with a sequence of actions ordered in time, but with events. So for your framework to be usable, you must provide hooks to:

    - do something at init
    - register a component
    - do something when a component is registered
    - do something once it's ready
    - do something when there is an error
    - do something when it shuts down
With minimum boiler plate, and maximum clear error handling when the user try to do it at the wrong time or in the wrong way.

But, we learned while coding the project that, with asyncio, exceptions in coroutine don't break the event look (except KeyboardInterrupt which is a weird hybrid) while exceptions from the loop do break it.

Plus you have to make a nice setup, which auto starts the event loop with good default so that people don't have to think about it for simple apps. But it must be overridable, and handle the case where your framework is embeded inside an already started event loop, and make it easy to do so.

It's one of the strong point of gevent: you don't have to think about it. With asycio/twisted, you have the benefit a explicit process switch and parallelism, but you need to pay the price with verbosity and complexity. We try to create a balance, and it's turns out to be harder than expected.

Then you have to make clear error reporting, especially iron the implementation mixing Task, Futures, coroutine functions and coroutines. Provide helpers so that common scheduling is done easily...

And you haven't even talked about HTTP yet. This is just proper asyncio management. This is why nobody made a killer framework yet : it's a looooooot of work, it's hard, and it's very easy to get it wrong. Doing like <sync framework> but async doesn't cut it.


You've basically described Twisted. It's unfortunate that when twisted was initially developed python didn't have some of the syntactic niceness (coroutines, async) that would have made it a bit easier/cleaner to use.


you are doing excellent work. you should totally join hands with the OP and make something great!!


sounds good! Go forth!


https://github.com/pyGrowler/Growler "A micro web-framework using asyncio coroutines and chained middleware."


Forgive me if I'm misunderstanding what you're looking for, but doesn't Tornado fit that bill?


Tornado still too low level.

    - It's verbose compared to flask.
    - It reinvent the wheel, while flask uses great components such as werkzeug.
    - If you want to make a component, it's complex.
    - It doesn't come battery included for the Web like Django, just the bare minimum.
    - It misses the opportunity to provide task queues, RPC or PUB/SUB which are key components to any modern stacks are made easily possible by having persistent connections.
    - It ignores async/await potential of unifying threads/process/asyncio and don't allow easy multi-cpu.
Don't get me wrong, I think tornado is a great piece of software, but it's not match against innovative projects we see in Go or NodeJS such as Meteor.


We will have to agree to disagree on many of your points as they are mostly personal opinions, but the last one is flat wrong. Tornado has for a long time had great support for fully leveraging all CPU cores. Happy to show sample code if you like.


My mistake. My knowledge on tornado is dated.


Yeah, it's hard for Python to compete with languages like Go and Erlang that multiplex IO in the runtime.


It's not hard for the language, but we don't have the proper framework yet. Because such a framework is quite a task.


I'm the main person in Django working on 2), and this is interesting for sure, though our current code is based on Twisted since we need python 2 compatability (there's some asyncio code, but not a complete webserver yet)


What are the chances that Django Channels (the project I believe you're working on) will be able to ship with support for asyncio/uvloop?


You can use guv[0] if you're looking for a UV based version of gevent. I've used it before with good success.

[0] https://github.com/veegee/guv/blob/develop/README.rst


The answer of 2) is likely to be "no" as wsgi is synchronous in nature. The only way to run it async is through gevent.


I'm working on a Python CLI that uses asyncio/aiohttp to make and process requests to a 3rd party API. Anyways, I ran into the 10,000 socket problem today and ended up using a semaphore, that actually boosted the overall performance. Why is that? Is it just because the CPU is overwhelmed otherwise?


It depends. Maybe you aren't closing the sockets properly (shutdown + close). Or maybe, because of how TCP works, the sockets are stuck in timeouts and don't really close for a long period of time. If its something like that, then your old connections aren't really closing, and new ones can't be created.

Or maybe it's a simple problem of aiohttp performance -- as shown in the blog post, its HTTP parser is a bit slow.

In general, I'd recommend to use a fewer number of sockets and implement some pipelining of API requests.


Are you making all connections within a single session?

Not long ago I saw example here that someone was creating a new session for every single connection. This is not very optimal way of using it. If you use it within same session, aiohttp will make use of keep-alive, which in turn will reuse existing connections and reduce overhead. You also won't need to use a semaphore, since you can define limit in TCPConnector.

Why you had performance issues? As other said, you were making thousands of connections, each socket need to be in TIME_WAIT state for 2 minutes after closing (limitation of TCP, SCTP does not have this problem). So if you use all connections within short time, you'll essentially run out of them. Some people use tcp_tw_reuse/recycle, and that solves this issue, but that makes your connections no longer follow RFC and you might encounter strange issues later on. The advice above should resolve your problem without any hacks.


> at least 2x faster than nodejs, gevent, as well as any other Python asynchronous framework

I did not see any benchmarks in the repo to support this. How was this statistic determined?


For benchmarks we have a separate project on the GH: [1] -- you can run the benchmarks on a Linux box pretty easily. Here's an example output: [2]

[1] https://github.com/MagicStack/vmbench [2] http://magic.io/blog/uvloop-blazing-fast-python-networking/t...


Not sure what you mean, the benchmark section lists ~40k packets/s for nodejs and asyncio, ~100k for uvloop (for 1KiB packages, similar difference for 10 and 100 KiB) - and ~20k req/s for nodejs, and ~37k for uvloop w/httptools. Interestingly, uvloop pulls ahead for 100KiB request size for the http case.


The benchmark (simple echo server) results were right there in the blog post:

http://magic.io/blog/uvloop-blazing-fast-python-networking/t...


Building on to this, how does it compare to raw libuv in c?Personally, I'm not surprised that python (especially cython) is faster than node in this case, but I still need to see how much less overhead there is to node.


> Building on to this, how does it compare to raw libuv in c?

Building something in C is very hard. uvloop wraps all libuv primitives in Python objects which know how to manage the memory safely (i.e. not to "free" something before libuv is done with it). So development time wise, uvloop is much better.

As for the performance, I guess you'd be able to squeeze another 5-15% if you write the echo server in C.

> I'm not surprised that python (especially cython) is faster than node in this case

Cython is a statically typed compiled language, it can be anywhere from 2x to 100x faster than CPython.


>So development time wise, uvloop is much better.

Yeah, I definitely get that. I'm just trying to see the smaller picture here.

>Cython is a statically typed compiled language, it can be anywhere from 2x to 100x faster than Python.

Ah, my bad for not knowing the difference between Cython and CPython. It seems to me, then, that this isn't really a fair comparison to node, is it? Naturally a statically typed language is going to be faster than a dynamic one. Good on you for including a comparison with Go, though.


> It seems to me, then, that this isn't really a fair comparison to node, is it?

Isn't node written in C?


Yes, but JavaScript is still a dynamic, garbage collected language.


Most of nodejs internals are in C++ on top of libuv. Only a thin layer of JS interfaces wrap that.

Python is also a dynamic, GCed language. uvloop is built with Cython, which uses the Python object model (and all of its overhead!), and CPython C-API extensively (so it's slower than a pure C program using libuv).


I think the uvloop package is written in Cython, but the benchmarks just use Python.


What are some of the non-obvious limitations/peculiarities one should be aware before using this?


Wherever you use asyncio, it should be safe to just start using uvloop (once we graduate it from beta).

uvloop shouldn't behave any differently, I've paid special attention to make sure it works exactly the same way as asyncio (down to when its objects are garbage collected).


Pretty awesome stuff. Do you think aiohttp's http parsing would benefit much on a hypothetical pypy3 interpreter?


Maybe. But I think its parser is better to be replaced with the httptools one.


It looks like uvloop requires Python 3.5. How practical is it to create a fork for companies stuck on Python 2.7?


Not really practical. uvloop is designed to work in tandem with asyncio, which is a Python 3-only module. asyncio, in turn, requires 'yield from' support, something that Python 2 doesn't have.


The 'Trollius' module backported asyncio to Python 2, requiring syntax changes, though. For example "yield from" to "yield From()".

Work on Trollius was stopped a few weeks ago, there wasn't enough interest/use. Call for interested maintainers, http://trollius.readthedocs.io/deprecated.html#deprecated


The problem with Trollius was that packages that asyncio packages needed explicitly to add support for it to work (because Python 2 does not have yield from) Several packages (I remember aiohttp was one of them) did not want to do that.


> How practical is it to create a fork for companies stuck on Python 2.7?

Not very, it's an alternative event loop for asyncio[0] which was introduced in 3.4 and builds upon other Python 3 features (e.g. `yield from`)

[0] https://docs.python.org/3/library/asyncio.html


Use either docker or/and crossbar.io to isolate the 2.7 code as a service if you don't want to port it, then add the rest of the code in 3.


Today it should be good practice to use containers with Python 2.7 and 3.5 or any other versions you like. With that you can solve most szenarios.


Python is actually designed in such way that you can install multiple major versions and they can coexist perfectly fine together.

For example you can install python 2.6, 2.7, 3.3, 3.4, & 3.5 all on one host without any conflicts. The limitation is that many distributions prefer to not maintain different versions of supposedly the same language.

If you use RedHat or CentOS you can just use https://ius.io/ and get access to the other python versions. This is one of few repos that makes sure the packages don't conflict with system ones.


This is awesome!

How does it compare to PyPy?

Once PyPy3 is available, will this work with it?


> Once PyPy3 is available, will this work with it?

We'll find a way!


do you have perf benchmarks under heavier concurrency? (e.g., how does it do with 100 concurrent clients? 1000?)


The HTTP benchmarks were actually run under concurrency level of 300. I've just updated the post with extra details. See also the full report of HTTP benchmark [1]

[1] http://magic.io/blog/uvloop-blazing-fast-python-networking/h...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: