[Zope3-dev] Asyncore (and Twisted)

Itamar Shtull-Trauring itamar@itamarst.org
Wed, 30 Oct 2002 14:05:50 -0500


(I am not a subscriber, please CC me.)

Guido van Rossum wrote:

> IMO (after having worked with it extensively in ZEO/zrpc) asyncore is
> a really small piece of functionality that you'll need no matter how
> you slice it, if you don't want to do all your I/O synchronously
> (which would mean one thread per connection).

It's also badly designed, encourages bad design, and is inherently
limited.

1. asyncore.dispatcher has readable() and writable() methods that get
polled in each iteration of the event loop. This assumes the
multiplexing API doesn't keep state - which is in fact how select()
works. Other mechanisms *do* keep state, e.g. I think kqueue does, so
asyncore will need extra work to use them , or possibly can't use them
at all in an efficient way.

2. It encourages you to tie the protocol and the networking code (the
transport) together into one class. This makes supporting other
networking systems very hard, or even impossible.

3. Asyncore is tied to the socket module. This works nicely until you
reach the point where you don't want to use the socket module for
networking (say, you're using pyOpenSSL and don't really feel like
making a new subclass for each of your protocols, or see below).

These issues combine into making sure asyncore will probably never:

a. Support Win32 I/O Completion Ports, which is the only scalable
networking I/O system on Windows NT (select() is by default hardcoded to
only 64 fds on WinNT to encourage you not to use it). IOCP use real
async I/O, their model is a proactor design pattern as opposed to
asyncore's reactor design pattern, and you use win32all-wrapped APIs
instead of socket module. I had experimental code supporting IOCP for
Twisted, though. Like POSIX AIO will never work in asyncore.

b. Have a C networking core that does the TCP transfer code as well
(buffering and so on). Twisted has a broken C core, which I'm told has a
lot of potential for speed. I know someone who says he's written fast C
reactor for Twisted using Linux's /dev/poll and it's "significantly
faster", but that code is unreleased.

The design issues can however be worked around, of course. But look at
http://twistedmatrix.com/products/echo_server -- notice the Twisted
protocol doesn't have to know anything about the transport, whereas the
asyncore code is tied to socket module, TCP and is in general ugly
(admittedly dispatcher_with_send would solve some of the ickyness).

> The one problem with asyncore is that it doesn't work well in a
> threaded environment: if thread A is executing the asyncore main loop
> and blocked in a select() or poll() call for file descriptors x and y,
> and thread B adds file descriptor z to the set of filedescriptors of
> interest, thread A won't wake up until x or y is ready, or until it
> times out.  The solution for this is pretty icky (in part because
> asyncore doesn't provide one itself, so the solution has to hack into
> asyncore's internals).  I don't know what Twisted does -- is it any
> better?

Twisted doesn't let you directly write to sockets from threads. However,
it lets you wake up the event loop thread, and you can do:

   reactor.callFromThread(someNonThreadSafeAPICall, arg1, a=b)

and the event loop thread is woken, and the method will be called in the
next iteration of the event loop in the event loop thread.

This queuing can be a performance issue for situations where you want to
have threads doing the networking directly (as Zope3 does), but given
the motivation the APIs might be extended to support networking calls
directly from threads.

In many other situations you don't need threads at all, or can use
threads in the reverse direction (dispatch blocking stuff to thread
pool, get back result, write to socket in event loop thread) which is
how Twisted e.g. supports blocking RDBMS calls
(http://twistedmatrix.com/documents/howto/enterprise.html).

-- 
Itamar Shtull-Trauring    http://itamarst.org/
Available for Python, Twisted, Zope and Java consulting
***> http://VoteNoWar.org -- vote/donate/volunteer <***