[Stackless] Just Not Getting One Aspect of Tasklets and Channel Receive on Pong Example

Carl, Andrew F (AS) a.carl at ngc.com
Mon Mar 15 19:03:44 CET 2010


Christian,

                Thanks for the reply and link to the stackless
documentation. Seemed like there should be more than just the PDF.
Regarding your reply, the part which is unclear is the implication of a
tasklet which contains a channel receive. I understand the functionality
and blocking, but it would seem that "stackless.tasklet(...)()" places
an instance of a "callable" on the stackless queue. But once the tasklet
channel send is accomplished, that tasklet would be complete and exit
out of the queue, no longer available to channel receive. It is for this
reason that it appears that a new tasklet is being placed in the queue
as a result of a channel send. It would seem that the proper sequence
would be as follows:


def ping():

    accum_ping = accum_ping + 1
    while ping_channel.receive(): #blocks here
        print "PING"

  if accum_ping > 1:

      stackless.tasklet(pong)()   #so there would be a pong task
available to channel receive after all calls subsequent to the 1st time
pong is called
        pong_channel.send("from ping")

def pong():
    accum_pong = accum_pong + 1
    while pong_channel.receive():
        print "PONG"
        if accum_pong > 1:

      stackless.tasklet(ping)()   #so there would be a ping task
available to channel receive after all calls subsequent to the 1st time
ping is called
        ping_channel.send("from pong")


Hope this illustrates what I'm trying to get my head around.

Thanks,

Andy

 

From: stackless-bounces at stackless.com
[mailto:stackless-bounces at stackless.com] On Behalf Of Christian Tismer
Sent: Saturday, March 13, 2010 8:35 AM
To: The Stackless Python Mailing List
Subject: Re: [Stackless] Just Not Getting One Aspect of Tasklets and
Channel Receive on Pong Example

 

On 3/12/10 9:44 PM, Carl, Andrew F (AS) wrote: 

The pong example on p. 13 of the "Why Stackless" manual is unclear to
me.  It appears that the tasklet statement puts the task on the queue
once, but yet it seems that the send to the "while receive" is
effectively creating another tasklet on the queue. It would seem that
they should bounce back and forth only once each without the addition of
a new tasklet statement. Could someone please clarify this?

An unambiguous link would be preferrable to readers, like this:

http://members.verizon.net/olsongt/stackless/why_stackless.html#pingpong
-stackless-py-stackless-ping-pong-example

#
# pingpong_stackless.py
#

import stackless

ping_channel = stackless.channel()
pong_channel = stackless.channel()

def ping():
    while ping_channel.receive(): #blocks here
        print "PING"
        pong_channel.send("from ping")

def pong():
    while pong_channel.receive():
        print "PONG"
        ping_channel.send("from pong")



stackless.tasklet(ping)()
stackless.tasklet(pong)()

# we need to 'prime' the game by sending a start message
# if not, both tasklets will block
stackless.tasklet(ping_channel.send)('startup')

stackless.run()


Assuming that this is the code you are referring to, I am trying
to understand your question.

Two tasklets are created which are initially blocking on their channel.

stackless.tasklet(ping)()
stackless.tasklet(pong)()

Going into details:

stackless.tasklet(ping)

is the constructor call of a tasklet, bound to function ping.
A more explicit notation would be

task = stackless.tasklet()  # not bound to a function
task.bind(ping)             # bound to ping
task.setup()                # set empty argument list

After the setup, the ping tasklet is ready to run. It is sitting in
the runnables queue, right after the implicit main tasklet.

The same thing as above repeats for the pong tasklet.

stackless.tasklet(pong)()

We have a circular list of runnable tasklets:

main     <-    still executing
ping    |  |   paused
pong     ->    paused

Now we enter the last line before the run():

# we need to 'prime' the game by sending a start message
# if not, both tasklets will block
stackless.tasklet(ping_channel.send)('startup')

This tasklet does the equivalent of

    ping_channel.send('startup')

but it is written in this deferred form, so that all tasklet activities
are done
in the run() context. This is not needed for the example to work, but
seems
to be the author's intent, for more clarity.

We have now the following circular queue picture:

main     <-    still executing
ping    |  |   paused
pong    |  |   paused
<???>    ->    paused
 

Now we enter the final statement, which does it all:

stackless.run()

Main gets removed from the runnables queue, to let the other tasklets
do their thing. ping is the next available tasklet and it runs:

ping     <-    current
pong    |  |   paused
<???>    ->    paused
 

ping starts to run, but immediately blocks on the empty ping_channel:

def ping():
    while ping_channel.receive(): #blocks here
        print "PING"
        pong_channel.send("from ping")

ping gets removed from the runnables queue and stored in the
ping_channel. So the next available tasklet is pong.

pong     <-    current
<???>    ->    paused
 
def pong():
    while pong_channel.receive():
        print "PONG"
        ping_channel.send("from pong")
 

The same happens to pong, since pong_channel is empty.
It gets blocked into pong_channel. Our only available
tasklet is now the nameless <???>.

<???>    <->   current. sends 'startup' on ping_channel
               and exits.

Now we are back in ping, right after the receive call. ping is
our only active tasklet:

ping     <->   current. prints 'PING', then sends
               'from ping' on pong_channel.
 
def ping():
    while ping_channel.receive(): #blocks here
        print "PING"
        pong_channel.send("from ping")
 
PING
 

ping gets blocked after sending on pong_channel, and pong
is now our only active tasklet:

pong     <->   current. prints 'PONG', then sends
               'from pong' on ping_channel.
 
PONG

Now that game continues until you hit CTL-C. The main tasklet will then
wake up and report the exception.

hope this helps -- chris
 
 
p.s.:
If people have questions like this, I'd like to refer them to
http://www.disinterest.org/resource/stackless/2.6.4-docs-html/stackless-
python.html
This is the one and only reference documentation that covers it all!

-- 

Christian Tismer             :^)   <mailto:tismer at stackless.com>
<mailto:tismer at stackless.com> 
tismerysoft GmbH             :     Have a break! Take a ride on Python's
Johannes-Niemeyer-Weg 9A     :    *Starship* http://starship.python.net/
14109 Berlin                 :     PGP key -> http://wwwkeys.pgp.net/
work +49 30 802 86 56  mobile +49 173 24 18 776  fax +49 30 80 90 57 05
PGP 0x57F3BF04       9064 F4E1 D754 C2FF 1619  305B C09C 5A3B 57F3 BF04
      whom do you want to sponsor today?   http://www.stackless.com/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.stackless.com/pipermail/stackless/attachments/20100315/726f833a/attachment.htm>


More information about the Stackless mailing list