[Python-Dev] 'stackless' python?

Tim Peters tim_one at email.msn.com
Mon May 17 07:42:59 CEST 1999


[Sam]
> Continuations are more powerful than coroutines, though I admit
> they're a bit esoteric.

"More powerful" is a tedious argument you should always avoid <wink>.

> I programmed in Scheme for years without seeing the need for them.
> But when you need 'em, you *really* need 'em.  No way around it.
>
> For my purposes (massively scalable single-process servers and
> clients) threads don't cut it... for example I have a mailing-list
> exploder that juggles up to 2048 simultaneous SMTP connections.  I
> think it can go higher - I've tested select() on FreeBSD with 16,000
> file descriptors.

The other point being that you want to avoid "inside out" logic, though,
right?  Earlier you posted a kind of ideal:

    Recently I've written an async server that needed to talk to several
    other RPC servers, and a mysql server.  Pseudo-example, with
    possibly-async calls in UPPERCASE:

      auth, archive = db.FETCH_USER_INFO (user)
      if verify_login(user,auth):
          rpc_server = self.archive_servers[archive]
          group_info = rpc_server.FETCH_GROUP_INFO (group)
          if valid (group_info):
              return rpc_server.FETCH_MESSAGE (message_number)
          else:
              ...
          else:
              ...

I assume you want to capture a continuation object in the UPPERCASE methods,
store it away somewhere, run off to your select/poll/whatever loop, and have
it invoke the stored continuation objects as the data they're waiting for
arrives.

If so, that's got to be the nicest use for continuations I've seen!  All
invisible to the end user.  I don't know how to fake it pleasantly without
threads, either, and understand that threads aren't appropriate for resource
reasons.  So I don't have a nice alternative.

> ...
>   | >>> import callcc
>   | >>> saved = None
>   | >>> def thing(n):
>   | ...     if n == 2:
>   | ...             global saved
>   | ...             saved = callcc.new()
>   | ...     print 'n==',n
>   | ...     if n == 0:
>   | ...             print 'Done!'
>   | ...     else:
>   | ...             thing (n-1)
>   | ...
>   | >>> thing (5)
>   | n== 5
>   | n== 4
>   | n== 3
>   | n== 2
>   | n== 1
>   | n== 0
>   | Done!
>   | >>> saved
>   | <Continuation object at 80d30d0>
>   | >>> saved.throw (0)
>   | n== 2
>   | n== 1
>   | n== 0
>   | Done!
>   | >>> saved.throw (0)
>   | n== 2
>   | n== 1
>   | n== 0
>   | Done!
>   | >>>

Suppose the driver were in a script instead:

thing(5)           # line 1
print repr(saved)  # line 2
saved.throw(0)     # line 3
saved.throw(0)     # line 4

Then the continuation would (eventually) "return to" the "print repr(saved)"
and we'd get an infinite output tail of:

Continuation object at 80d30d0>
n== 2
n== 1
n== 0
Done!
Continuation object at 80d30d0>
n== 2
n== 1
n== 0
Done!
Continuation object at 80d30d0>
n== 2
n== 1
n== 0
Done!
Continuation object at 80d30d0>
n== 2
n== 1
n== 0
Done!
...

and never reach line 4.  Right?  That's the part that Guido hates <wink>.

takes-one-to-know-one-ly y'rs  - tim






More information about the Python-Dev mailing list