Microthreads without Stackless?

Patrick Maupin pmaupin at speakeasy.net
Sun Sep 19 01:57:55 EDT 2004


> As both Bryan and some other folks upthread point out, *FLAT*
> coroutines don't mix well directly with a callstack.  There
> are things you can do that use both, but reasoning about your
> programs becomes more difficult, and you probably need extra
> code.  But you REALLY don't lose anything by moving an explicit
> callstack out of a function/generator object, and into the
> overall flow of your program.

I agree in principle, but it's the same principle that says that a
Turing machine is a viable computer, or that you can emulate
coroutines with regular unthreaded programming.  In other words, to
me, the whole point of using coroutines is to make reasoning about the
system easier (of which reducing code is sometimes a large part). (So
color me un-academic :)

For example, it's only a start to be able to build a filter as an
endless loop which calls a function to get data, then calls a separate
function to be able to put the data.  The whipped cream and cherry is
when the get and put functions can do arbitrary things, including
blocking (e.g. by yielding to a coroutine) at will, for example to
allow another coroutine to fill or empty a buffer.

By the way, since there was so much confusion in this thread on
exactly what a coroutine *is* and what its capabilities are, I did a
little research.  Most of the relevant documentation is pre-web (or
hidden behind pay-per-use systems), but I did find one excellent,
up-to-date public resource, "Revisiting coroutines" by Ana L´ucia de
Moura and Roberto Ierusalimschy, at:

http://www.inf.puc-rio.br/~roberto/docs/MCC15-04.pdf

One of the interesting tidbits I got out of this paper is that Lua
supports full coroutines.  I definitely need to look into Lua
sometime.

I have reproduced the section on "Stackfulness" from the paper below.

Regards,
Pat


2.3 Stackfulness

Stackful coroutine mechanisms allow coroutines to suspend their
execution from within nested functions; the next time the coroutine is
resumed, its execution continues from the exact point where it
suspended. Stackful coroutine mechanisms are provided, for instance,
by Simula, BCPL, Modula-2, Icon, and also by CLU and Sather's
iterators.

A currently observed resurgence of coroutines is in the context of
scripting languages, notably Python and Perl. In Python [Schemenauer
et al. 2001], a function that contains an yield statement is called a
generator function. When called, this function returns an object that
can be resumed at any point in a program, so it behaves as an
asymmetric coroutine. Despite constituting a first-class object, a
Python generator is not a stackful construct; it can only suspend its
execution when its control stack is at the same level that it was at
creation time. In other words, only the main body of a generator can
suspend. A similar facility has been proposed for Perl 6 [Conway
2000]: the addition of a new type of return command, also called
yield, which preserves the execution state of the subroutine in which
it is called.

Python generators and similar non-stackful constructs permit the
development of simple iterators or generators but complicate the
structure of more elaborate implementations. As an example, if items
are produced within recursive or auxiliary functions, it is necessary
to create an hierarchy of auxiliary generators that yield in
succession until the original invocation point is reached. This type
of generator is also not powerful enough to implement user-level
multitasking.



More information about the Python-list mailing list