Microthreads without Stackless?

David Mertz, Ph.D. groups.google at gnosis.cx
Fri Sep 17 14:09:36 EDT 2004


Michael Sparks <michaels at rd.bbc.co.uk> wrote in message news:
> The real root of the 'problem' "Bryan Olson" is putting forward is the
> fact that you can only jump between yield points in simple generators,
> which are inherently single level, rather than nested. (ie the
> traditional "you can't wrap generators" question)

Yeah... I know Bryan thinks that's a problem.  Mostly because he
doesn't actually know what a coroutine is.  But it's true that the
scheduled coroutines I present in the mentioned article are always
"flat" (hmm... didn't I read somewhere that: "Flat is better than
nested"?)

But that's actually just what coroutines ARE.  Bryan seems to want
some kind of hybrid between actual coroutines and a call stack.  Which
isn't necessarily bad.  And is probably something various
languages--like Perl 6--do support.

It might also be something that your greenlets support.  It looks like
an interesting project, and I'll have to take a look at it soon, and
maybe do an article on them.  But I suspect that even there, Bryan
won't get everything he wants with his additional constraint that he
not have to "change any code."

I'm sure Michael gets the distinction, but for other readers, I'll
point out that my coroutine schedules probably does require a little
reorganization of more traditional call-chain code.  For example, you
might want to modify traditional program to allow arbitrary switches
in flow control using (pseudo-code):

  def parent():
      ....do stuff...
      child()
      return

  def child():
      ...do stuff...
      yield to uncle
      return to parent

  def uncle():
      ...stuff...
      yield (back) to child # nephew, I guess

That won't work with my generator/coroutines using a scheduler.  
'child()' can only yield one level up, not arbitrarily.  But you can
"flatten" the exact same flow by making it:

  def parent():
      ...do stuff...
      yield to child
      return

  def child():
      ...do stuff...
      yield to uncle
      yield (back) to parent

  def uncle():
      ...stuff...
      yield (back) to child

This is pseudo-code, of course.  But it's not much different from in
my article.  The point is just the 'child()'  can't be *called* from
'parent()', but rather must be *switched* to (via the scheduler, and a
yielded "next coroutine").  In terms of what code is executed when,
it's exactly the same thing... but there *are* some nominal changes
needed in the way you write the code.

Yours, David...



More information about the Python-list mailing list