Archive

Posts Tagged ‘python’

gevent 0.13.6 released

May 2, 2011 3 comments

This is a maintenance release, with a few issues fixed by the users.

Thanks to Galfy Pundee, Alexander Boudkar and Alexey Borzenkov.

Read the (relatively short) changelog entry, download it from PyPI.

Categories: Announcement Tags: ,

libev and libevent

April 28, 2011 20 comments

The next version of gevent (1.0) will use libev for the event loop rather than libevent or libevent2. In this post I’ll explain the reasons behind the switch.

But first let’s revisit the original reasons for choosing libevent1.4 over libev:

  •  I considered it more popular and more proven
  •  It’s packaged in Debian (apt-get install libevent libevent-dev)
  •  It has dns, http and bufferevents

However, I no longer consider any of this reasons important.

First of all, libev has been used in lots of projects since then and underwent lots of scrutiny.

Second, most distributions do not package the latest versions of both libraries so the argument that gevent with libevent is easier to install becomes moot. Actually,  libev is really easy to embed and that’s what we’re going to do for the next version: put all the dependencies in the release tarball. Hopefully this will reduce the number of build problems people get. This will also remove the number of possible variations of gevent because of different library versions used. There still will be an option to dynamically link against the dependencies, it just won’t be the default.

The third argument that libevent has built in support for dns and http still holds. And it is part of what makes gevent cool, but now it’s time to move on.

For example, I encountered the following bugs in Libevent’s dns/http implementation:

  • [dns] random failures and timeouts
  • [dns] forking breaks it completely (issue #2)
  • [dns] /etc/resolv.conf is not handled correctly
  • [http] data corruption when pipelining (thus pipeline is disabled by default)
  • [http] no streaming support
  • [http] random failures in client

I have most experience with libevent1.4 but brief tests and gevent’s test suite show that neither libevent-dns nor libevent-http became solid with the release of libevent2.0.10-stable.

Every time I try to fix one of these issues I find the implementation of libevent-dns/libevent-http unreasonably complex for what they do.

Some of the complexity seem to spur from the fact that libevent2 tries to be thread-safe and this affects the control flow: instead of executing a callback directly, libevent2 authors have to use deferred queues of callbacks to avoid deadlock. So thread-safety of libevent2 has cost in complexity but no benefits for Python programs.

Because libev is just an event loop, we need to replace libevent-dns and libevent-http with something. There’s a port of libevent-dns that works with libev, but there’s no particular reason to use it (other than ease of integration since we already have wrappers for it). I’ve done some experiments with c-ares library (used by curl, among others) and really like the results.

The c-ares library is about twice as large as libevent-dns but I find the code to be much easier to follow. Using c-ares + libev fixed all [dns] issues mentioned above. In addition, gevent.socket now also provides “green” versions of getnameinfo and gethostbyaddr.

Neither c-ares nor libev are thread-safe which is good there.

Now, let’s keep aside libevent’s addons and look at the event loops provided by libev and libevent.

1. Design

In libevent there’s a big multi-functional event class, which is used for

  • I/O readiness notifications
  • timeouts
  • signals (by passing signalnum instead of fd and setting the EV_SIGNAL flag)

The signal handling is an obvious afterthought here, but even I/O notifications and timeouts should be separated, as quite often you only need one of them. Note, that libevent does provides macros (“evtimer_” and “evsignal_”) that imitate “orthogonal” interface but I’m talking about the implementation here.

In libev all of the above provided by different, clearly separated “classes” called “watchers”.

There’s a minor difference is that libevent’s events are one-shot by default (unless used with EV_PERSIST flag) and libev’s watchers are “persistent” in libevent parlance – they must be explicitly cleared.

There are also watchers without analogs in libevent:

a) ev_prepare and ev_check watchers

Those unconditionally run the associated callback before and after “poll” call. This is useful for signal handling.

The way gevent works is by running the event loop forever in a separate greenlet. One downside of that is that Python cannot execute the signal handlers installed with the standard “signal” module. Of course, there’s signal handling integrated with the event loop, that both libev and libevent provide (exposed as gevent.signal) but that is different from the signal module:

  • it won’t work if some Python code is busy looping and the event loop is starving, as it gets dispatched by the event loop
  • it has different interface and thus not easily monkey patched
  • (on Windows) signal module emulates Ctrl-C signal with WINAPI and neither libev nor libevent do that.

In gevent 1.0, I use ev_prepare to check for Python signals and execute the signal handlers. The end result is that the standard “signal” module now “just works” with gevent. And gevent.signal is also there if you need it.

b) ev_child watcher

This will come handy when implementing gevent.os and gevent.subprocess modules.

c) ev_idle watcher

This executes a callback if the event loop is idle. I think it can be used to integrate other event loops into gevent’s loop (for example, a gui app). I don’t think libevent2 has a way to achieve that – embed another event loop.

I also like the names better, that is “loop” rather than “event_base”, “watcher” rather than “event”.

Marc Lehmann, the author of libev also wrote Perl wrappers for libev and a Coroutine library for Perl, which might explain why the libev API is a good fit for wrapping in a high-level language.

2. Implementation

Both libevent and libev support epoll, kqueue, poll, select, solaris event ports.

Where libevent is nicer than libev is Windows support.

On Windows, libevent accepts Windows handles instead of C runtime file descriptors. Python uses Windows handles too, so gevent happily passes socket’s fileno() to libevent. Libev uses C runtime handles, so we need to convert Windows handles into C runtime handles.

Libevent2 also supports IOCP, via  asynchronous bufferevents. However this feature is marked as experimental and neither libevent-http nor libevent-dns use it. Gevent does not wrap bufferevents, so gevent 0.13 is not benefiting from IOCP even if compiled with libevent2.

Thus, I do not expect performance downgrade on Windows when upgrading from gevent 0.13 to gevent 1.0.

Read the discussion on the mailing list that prompted to write this post.

Note, that mere switch from libevent to libev is not the only change in gevent 1.0. Rather, the whole core have been redesigned. I plan to make a blog post some time soon about this.

Thanks to Nicholas Piël for corrections.

gevent 0.13.4 released

April 11, 2011 Leave a comment

This is a maintenance release, fixing a number of issues.

Read the changelog, download it from PyPI.

Thanks to Shaun Lindsay, Nick Barkas, Andreas Blixt.

Categories: Announcement Tags: ,

gevent on PyCon

March 17, 2011 Leave a comment

Using Coroutines to Create Efficient, High-Concurrency Web Applications
In this talk Matt Spitz evaluates several ways to deploy WSGI applications. At Meebo, they settled on gunicorn + gevent, preferring it to mod_wsdi and Twisted.

PyCon 2011: An outsider’s look at co-routines.
This is an overview by Peter Portante that compares greenlet-based approaches like gevent with yield-based coroutines and threads.

Categories: Advocacy Tags: ,

Gevent joins The Software Freedom Conservancy

January 18, 2011 Leave a comment

I’m pleased to announce that Gevent is now a member of The Software Freedom Conservancy. The SFC is a not-for-profit organization that provides financial and administrative assistance to open source projects.

Among other things, the SFC will accept the tax-deductible donations on behalf of Gevent that will go the project’s fund.

Categories: Announcement Tags:

Comparing gevent to eventlet

February 27, 2010 5 comments

In this post I try to explain why gevent was started and how it is compares to eventlet.

Note: gevent has switched to libev.

History

Bob Ippolito wrote the first version of Eventlet in 2006 but ceased working on it fairly early. Donovan Preston took over the maintenance, together with other folks at Linden Lab where he worked at the time. I became interested in Eventlet in 2008, when I was looking for simpler ways to write networking software than with state machines and callbacks. Greenlet-based Eventlet was ahead of the other options that existed at the time (Python’s native generators, raw greenlet, Corotwine) in terms of features and easiness of use.

The project I worked on already depended on Twisted, so I started integrating the two libraries together. In the process of doing that I discovered a number of bugs in Eventlet and ended up rewriting most of its core. My branch was accepted as the way forward and finally released in 2009 as Eventlet 0.8.11. By that time Donovan had already left Linden Lab and Ryan Williams became the primary maintainer.

In the summer of 2009, I have started a new project where a networking library was going to be a major component. However, Eventlet did not meet a couple of requirements:

  • I needed it to use libevent’s event loop because I had another library (written in C) that used it and I wanted to integrate them together in a single process. Eventlet at the time did not have a working libevent support.
  • I needed socket module to work perfectly as I planned to use Python libraries implemented on top of it through monkey-patching. At the time Eventlet had a few bugs that could cause a socket operation to hang.

I have spent some time working on the pyevent-based hub. The result was not very compatible with the rest of Eventlet due to the fact that its Hub API is geared towards pure Python event loops. Making it work smoothly would require significant changes in the interface and implementation of every other hub. The socket module bugs were also specific to event loop, so even though I fixed them for pyevent, they were still present in every other hub. Not having time for a major rewrite of Eventlet I started a leaner project.

Gevent started as Eventlet with a few bugs fixed and a few features dropped.

The differences

1. gevent is built on top of libevent

Update: since 1.0, gevent uses libev and c-ares.

Libevent is a popular portable event loop. It runs your app using the fastest mechanism available on your system, such as epoll on Linux, and kqueue on FreeBSD. Unlike Eventlet, which maintains its own event loops in pure Python and has only recently gained epoll support, all of gevent’s event loops have been well-tested in real-world, high-scale environments.

The superior performance is one of the benefits of tight integration with libevent, but not the only one. Other benefits are

  • Signal handling is integrated with the event loop.
  • Other libevent-based libraries can integrate with your app through single event loop.
  • DNS requests are resolved asynchronously rather than via a threadpool of blocking calls.
  • WSGI server is based on the libevent’s built-in HTTP server, making it super fast.

2. gevent’s interface follows the conventions set by the standard library

For example, gevent.event.Event has the same interface and the same semantics as threading.Event and multiprocessing.Event but works across greenlets. Eventlet has Event class too, but it uses its own way of doing things for no good reason.

I’ve used the standard interfaces in gevent unless a brand new interface has an obvious advantage. In some cases, where re-implementing the whole class wasn’t necessary, the conventions on the method names set by the standard library were followed.

Here are some of those conventions:

  • wait() does not raise an exception;
  • get() can raise an exception or return a value;
  • join() is like wait(), but for units of execution.

Having consistent interface improves the speed at which we can read and reason about the code. Learning the API becomes easier as well.

Not being constrained by backward compatibility, gevent fixed all the API quirks that Eventlet had. The quality of the API is recognized by the users and Eventlet maintainers. Portions of gevent that are not specific to libevent are being incorporated into Eventlet.

3. gevent is not eventlet

It does not have all the features that Eventlet has. If you already use Eventlet these are the reasons why you might not be able to switch to gevent:

  • If you depend on eventlet.db_pool; gevent doesn’t have a module like that.
  • If you depend on eventlet.processes; there’s no support for subprocesses in the library yet. Here’s an example how to build it yourself.
  • If you depend on Eventlet’s threadpool; gevent does have one currently. Update: there’s a new gevent.threadpool module.
  • If you run Eventlet on Twisted reactor.
  • If you cannot depend on libevent.

Gevent aims to be a small and stable core everyone can depend upon. It delegates the job to libevent whenever possible and provides convenient abstractions for coroutine-based programming. It’s inspired by Eventlet but it’s not a fork and it features a new API. The implementation is simpler and more stable.

Read why others are choosing gevent and what you might encounter when porting from eventlet to gevent.

Thanks to Marcus Cavanaugh, Brad Clements, Nicholas Piël, Andrey Popp and Bob Van Zant for reading drafts of this.

Japanese Translation

Categories: Advocacy Tags: , , ,

gevent 0.12.0 is released

February 5, 2010 Leave a comment

Version 0.12.0 of gevent has been released on PyPI. Install it with

easy_install -U gevent

  • The major new feature is a gevent.ssl module, that provides cooperative implementation of the standard ssl module. It does not require any additional extensions on Python ≥ 2.6. It also works on 2.4 and 2.5 if ssl package is installed. The old, PyOpenSSL-based implementation of SSL objects is still available, but the new version is the preferred way now.
  • The library now compiles and passes most of the relevant tests on Windows. It’s still has a few rough edges (e.g. Ctrl-C is not working), so it should be considered experimental.
  • The socket object gained some performance improvements as well as a number of bugfixes.
  • Several incompatibilities of wsgi module with the WSGI spec have been fixed.

Read the details in the changelog.

Categories: Announcement Tags: ,