[Stackless] Stackless based replacement

Arnar Birgisson arnarbi at gmail.com
Fri Oct 3 00:16:29 CEST 2008


Hi Larry,

On Fri, Oct 3, 2008 at 00:06, Larry Dickson <ldickson at cuttedge.com> wrote:
> If I'm following you right, asynchronous IO is not needed. All that is
> needed is a loop on a non-blocking select

Non-blocking select is one form of asynchronous IO, right? Maybe we
differ in terminology here.

> (or, to avoid busyness, a select
> against the IO and one tick later than the last time noted by the loop). If
> you can put code into the virtual machine, it can be even cleaner: an
> unconditional swap out of the tasklet; whenever its turn comes up in the
> round robin, an unblocking select on its IO; and whenever all tasklets are
> waiting on IO, a blocking select on all outstanding IO.
>
> By dealing with the selects alone, you can emulate the occam ALT primitive
> which says "swap out until any of this list come ready." Old Inmos
> documentation shows how to get the state machine exactly right for that,
> including timers.

Instead of reinventing the wheel here, I'm in favour of using
mechanism that already handles this kind of thing. libevent and its
Python bindings pyevent is one. Regular files and network streams can
be (rudimentarily) emulated with some simple wrappers on channels (not
that this does timers too):

import time

import stackless
import event

def _loop():
    while _loop.running:
        event.loop(True)
        if stackless.getruncount() == 1:
            time.sleep(0.0001)
        stackless.schedule()
_loop.running = False

def init(interval=0.0001):
    """Initializes the libevent system and starts a tasklet that executes
    the libevent dispatcher on every round."""
    if _loop.running: return
    _loop.running = True
    stackless.tasklet(_loop)()

def stop():
    """Stops the libevent dispatcher tasklet."""
    if not _loop.running: return
    _loop.running = False

def sleep(seconds):
    """Sleeps the current tasklet for the specified number of seconds"""
    ch = stackless.channel()
    event.timeout(seconds, ch.send, None)
    ch.receive()

class ssfile(file):

    def __init__(self, *args, **kwargs):
        self.rch = stackless.channel()
        self.wch = stackless.channel()
        super(ssfile, self).__init__(*args, **kwargs)

    def read(self, *args):
        def cb():
            self.rch.send(super(ssfile, self).read(*args))
        event.read(self.fileno(), cb)
        return self.rch.receive()

    def write(self, *args):
        def cb():
            self.wch.send(super(ssfile, self).write(*args))
        event.write(self.fileno(), cb)
        return self.wch.receive()

stdfile = file
file = ssfile

import socket as stdsocket
class ssocket(stdsocket.socket):

    def __init__(self, *args, **kwargs):
        self.sendch = stackless.channel()
        self.recvch = stackless.channel()
        super(ssocket, self).__init__(*args, **kwargs)

    def send(self, *args, **kwargs):
        def cb():
            self.sendch.send(super(ssocket, self).send(*args, **kwargs))
        event.write(self.fileno(), cb)
        return self.sendch.receive()

    def recv(self, *args, **kwargs):
        def cb():
            self.recvch.send(super(ssocket, self).recv(*args, **kwargs))
        event.read(self.fileno(), cb)
        return self.recvch.receive()

    def accept(self, *args, **kwargs):
        def cb():
            self.recvch.send(super(ssocket, self).accept(*args, **kwargs))
        event.read(self.fileno(), cb)
        return self.recvch.receive()

cheers,
Arnar




More information about the Stackless mailing list