2010-05-18

Feature comparison of Python non-blocking I/O libraries

This blog post is a tabular feature comparison of Syncless and the 6 most popular event-driven and coroutine-based non-blocking (asynchronous) networking I/O libraries for Python. It was inspired by http://nichol.as/asynchronous-servers-in-python (published on 2009-11-22), which compares the features and the performance of 14 Python non-blocking networking I/O libraries. We're not comparing generator-based (yield) solutions here. We haven't made performance measurements, so speed-related claims in this comparison are beliefs and opinions rather than well-founded facts. Here are the results:

ConcurrenceEventletTornadoTwistedasyncoregeventcircuitsSyncless
pure Python: can work without compiling C codenoyesyesyesyesnoyesno
pure Python: runs at full speed without compiling C codenoyesyesyesyesnoyesno
standard module in Python 2.6nonononoyesnonono
has asynchronous DNS resolvernoyes, 1)noyes, 2)noyes, 3)noyes, 4)
supports running other tasklets while DNS resolving is in progressnoyesnoyesnoyesnoyes
has fully asynchronous and scalable DNS resolvernoyes, 5)noyesnoyesnoyes
supports timeouts on individual socket send() and recv() operationsyesyesnoyesnoyesnoyes
has WSGI serveryesyesyesyesnoyesyes--, 6)yes
can work with CherryPy's WSGI servernoyes--, 7)nononoyes--, 7)noyes
contains a custom, non-WSGI web frameworkyesnoyesyesnono++, 8)yesno
can run external web frameworks using non-WSGI connectorsnoyes, 9)nononononoyes++, 10)
runs with Stackless Pythonyesyes--, 11)yes, 12)yes, 12)yes, 12)noyes, 12)yes
runs with greenletyes--, 13)yesyes, 12)yes, 12)yes, 12)yesyes, 12)yes
has fast non-blocking socket class implemented in C or Pyrexnononononononoyes
has fast read and write buffer code implemented in C or Pyrexyesnonononoyes, 14)noyes
uses fast (C or Pyrex) buffer code for its socket.socket.makefile()yesnonononononoyes
uses fast (C or Pyrex) buffer code for its ssl.SSLSocket.makefile()no, 15)nonononononoyes
has SSL supportnoyes, 16)noyes, 16)noyes, 16)yes, 16)yes, 16)
has monkey-patchig for socket.socket and other blocking I/O operationsnoyesno, 12)no, 12)no, 12)yesno, 12)yes
prints and recovers from an uncaught exceptionyes, 17)yesyesyesyesyesno, 18)no, 19)
can use libeventyesyesnoyesnoyesnoyes
can use the libevent emulation of libevyesyesnoyesnono, 20)noyes
works without libevent or an emulation installednoyesyesyesyesnoyesyes
avoids C stack copying (which is slower than soft switching)nono, 21)yes, 12)yes, 12)yes, 12)no, 21)yes, 12)no, 22)
can use a high performance event notification primitive (e.g. epoll on Linux)yes, 23)yesyesyesno, 24)yes, 23)yesyes, 25)
nichol.as: What license does the framework have?yes, 26)yes, 26)yes, 27)yes, 26)yes, 26)yes, 26)yes, 28)yes, 29)
nichol.as: Does it provide documentation?yesyesyesyes++, 30)noyesyesyes--, 31)
nichol.as: Does the documentation contain examples?yesyesyesyesnoyesyesyes
nichol.as: Is it used in production somewhere?yes, 32)yes, 33)yes, 34)yesyes, 35)yes, 36)yes, 37)no
nichol.as: Does it have some sort of community (mailinglist, irc, etc..)?yesyesyes++, 38)yesnoyesyesno
nichol.as: Is there any recent activity?no, 39)yesyesyesnoyesyesyes
nichol.as: Does it have a blog (from the owner)?yesyesyes, 40)yes++, 41)noyesyesyes--, 42)
nichol.as: Does it have a Twitter account?yesyesyesyesnoyesyesyes--, 42)
nichol.as: Where can I find the repository? (without links)yes, 43)yes, 44)yes, 43)yes, 45)yes, 46)yes, 47)yes, 44)yes, 48)
nichol.as: Does it have a thread pool?noyesnoyesnonoyesyes--, 49)
nichol.as: Does it provide a HTTP server for WSGI applications?yesyesyes--, 50)yesnoyesyes--, 6)yes
nichol.as: Does it provide access to a TCP Socket?yesyesyesyesyesyesyesyes
nichol.as: Does it have any Comet features?nononononononono
nichol.as: Is it using epoll, if available?yes, 23)yesyesyesno, 24)yes, 23)no++, 51)yes, 25)
nichol.as: Does it have unit tests?yesyesnoyes++, 52)yesyesyesyes, 53)
provides generic timeout for any block of codeyesyesyesnonoyesnoyes
provides synchronization primitives (e.g. semaphore, codition variable)yes--, 54)yesnoyesnoyesnono
lets the programmer control event delivery order (e.g. with priorities)nononononononono
provides callbacks (links) when some work is finishednoyesyes, 12)yes, 12)yes, 12)yesyes, 12)no
has a high-level, comprehensive, consistent network programming frameworknoyesyes--, 55)yesno, 56)yes--, 55)yesno
has non-blocking select.select() implementationnoyesno, 12)no, 12)no, 12)yesno, 12)yes
implements some application-level protocols beyond HTTP, WSGI and DNSyes, 57)no++, 58)yes, 59)yes++, 60)nono++, 58)yes, 61)no++, 62)
compatible with other non-blocking systems in the same processno, 63)yes, 64)no, 63)yes++, 65)no, 63)no++, 66)yes, 67)yes++, 68)

Comments:
1) thread pool or Twisted
2) built-in
3) evdns
4) evdns or its equivalents: minihdns or evhdns
5) if Twisted is available
6) does not implement the WSGI spec properly (no write or close)
7) by manually monkey-patching socket and thread
8) has its own simple HTTPServer class
9) BaseHTTPServer
10) BaseHTTPServer, CherryPy, web.py, Google webapp
11) has partial, incomplete and incomatible greenlet emulation
12) event-driven
13) has partial and incompatible Stackless Python emulation
14) evbuffer
15) no SSL support
16) client and server
17) in the Tasklet class
18) sliently ignores exceptions and keeps the connection hanging
19) the process exits
20) needs evdns
21) uses greenlet
22) calls stackless.schedule() from C code
23) uses libevent
24) but uses poll and epoll could be added asily
25) can use libev or libevent
26) MIT
27) Apache
28) GNU GPL v2 or later
29) Apache License, Version 2.0
30) exensive
31) README and docstrings
32) Hyves.nl (a Dutch social networking site)
33) Second Life (a virtual reality game)
34) FriendFeed (a social networking site)
35) pyftpdlib, supervisor [link] (via medusa)
36) many, [link] and [link]
37) Naali, TAMS, website-profiler, kdb IRC bot, python-brisa uPnP
38) huge
39) not since 2009-11-19
40) at facebook
41) lots
42) the author writes Syncless-related stuff to his blog
43) GIT on github
44) Mercurial on bitbucket
45) in its own Subversion + Trac repository
46) in Python's Subversion
47) Mercurial on bitbuckig
48) Subversion on Google Code
49) not tested in production for robustness and speed
50) limited
51) it can be enabled manually
52) extensive
53) unit tests cover only parts of the functionality
54) provides queues
55) not comprehensive
56) low-level
57) MySQL client
58) Python console backdoor, can monkey-patch external modules
59) storage server compatible with Amazon S3; OpenID
60) tons of protocols
61) pygame, GTK+, inotify and pygame
62) can monkey-patch external modules
63) not by default
64) has Twisted reactor
65) many including GTK+ and Qt
66) not by default, but there is the project gTornado
67) pygame and GTK
68) has monkey-patching for Concurrence, Eventlet, Tornado, Twisted, gevent, circuits and asyncore

11 comments:

Nicholas Piƫl said...

Nice comparison, thanks! One thing this makes clear is the approach difference to protocols other than HTTP. At one side we have Concurrence, Tornado and Twitsed who provide their own extra libraries for some of these. And at the other side we have Eventlet, Gevent and now Syncless who can monkey patch IO operations.

Personally I really like the monkey patching approach as this allows you not only to have access to a huge array of libraries but at the same time it keeps the event-lib small.

Syncless looks really interesting as well. One thing that makes me wonder though is what its main focus is. On the one hand you have the focus on speed with the optimized socket handling and on the other hand you have the focus on compatibility with other frameworks. They don't really seem to be compatibly.

pts said...

Short answer to the compatibility question of Nicholas: In Syncless, speed and pure Python-compatibility (file, socket, SSLSocket) are the most important. Compatibility with other libraries is only a nice extra, but it doesn't affect the main design of Syncless, and doesn't make Syncless any slower if not used in a process.

bsdemon said...

As an aswer to "nichol.as: Is it used in production somewhere?" related to gevent — I am using gevent at some backend for facebook/vkontakte social games.

Christian said...

eventlet and gevent do work with cherrypy's wsgi-server quite well via monkey patching

pts said...
This comment has been removed by the author.
Denis said...

More info on gevent used in production:
http://groups.google.com/group/gevent/browse_thread/thread/4de9703e5dca8271

Giampaolo Rodola' said...

As an aswer to "nichol.as: Is it used in production somewhere?" related to asyncore — It is used in pyftpdlib (http://code.google.com/p/pyftpdlib) which has a discrete adoption list

chrism said...

Supervisor uses asyncore (via medusa), and it's in use in hundreds of production environments, FWIW.

pts said...

I've added circuits and updated the some cells based on other comments. Thanks for your informative comments!

Alexandre Bourget said...

Gevent has gevent-websocket and gevent-socketio which is a fully-fledged Socket.IO implementation, so does "Comet". See also pyramid_socketio for Pyramid integration.

Lindasy Rosenwald said...

Lindsay Rosenwald http://www.doctorlindsayrosenwald.com/dr-lindsay-rosenwald-prolific-leader/ Dr. Lindsay Rosenwald – The Most Prolific Leader