Microthreads without Stackless?

David Pokorny davebrok at soda.csua.berkeley.edu
Tue Sep 21 02:55:49 EDT 2004


"Bryan Olson":
> Michael Sparks:
> > [Try Greenlets]

> Finally, I think I understand the kind of stack-conjuring
> required to make coroutines work, and it's well outside standard
> Python's documented extension API.  I've been burned on that
> kind of thing before.

Before sending people off to greenlets, I'm starting to understand why you
have to go check them out via CVS---they are somewhat dangerous in their
current form. Fortunately, they come with a test that illustrates the
problem (as long as you compile Python in debug mode, but everyone does
that, right ;). To get a handle on what is going on here, the following
"test5" will leak, but calling "test5('noleak')" will not. I haven't the
foggiest idea why, and gc.collect() cleans up some but not all of the
excess.

David Pokorny

P.S. is this a subtle bug or what? BTW the code included here is a slight
modification of that given in the greenlets folder. Subclassing greenlets
killed my python---this is another mystery. Now I'm getting visions of
envious Wizard-of-Oz-munchkin-proletariats hacking away at a giant snake.
Time for bed.

-----------------------------
class genlet:
    def __iter__(self):
        return self
    def __init__(self,fn,args,kwargs):
        self.gl = greenlet.greenlet(fn,args,kwargs)
    def next(self):
        self.gl.parent = greenlet.getcurrent()
        result = self.gl.switch()
        if self.gl:
            return result
        else:
            raise StopIteration

def Yield(value):
    h = greenlet.getcurrent()
    h.parent.switch(value)

def generator(fn): #not used in this example
    def runner(*args, **kwds):
        return genlet(fn, args, kwds)
    return runner


# ____________________________________________________________

 #After running test5(), It turns out that frames of g
 #have frame->f_back == frame (such frames are found in
 #sys.getobjects(20)). Programs that leave
 #data in local variables will leak furiously.
 #Apparently gc.collect() doesn't want to clean it up.

def g(n):
    for i in range(n):
        Yield(i)
    return None

def test5(kind='leak'):
    def runner(*args, **kwds):
        x = genlet(g,args,kwds)
        return x
    if(kind == 'leak'):
        iteration = runner(10)             #<--leaks!
    else:
        iteration = genlet(g,(10,),{})     #<--does not leak.
    for j in iteration:
        print j
    iteration = None
    return None





More information about the Python-list mailing list