views:

220

answers:

2

I do not have stackless currently running, so I can not try this myself.

import stackless
ch1 = stackless.channel()
ch2 = stackless.channel()

ch1.send(ch2)
ch3 = ch1.receive()

Are ch2 and ch3 then the same channel? Say:

text = "Hallo"
ch2.send(text)
assert text == ch3.receive()

This feature reminded me of a talk about Newsqueak that Robert Pike (of Plan9 fame) gave at Google. In Newsqueak you could send channels over channels.

+3  A: 

Yes. Just tested.

>>> import stackless
>>> ch1 = stackless.channel()
>>> def a():
...  ch2 = stackless.channel()
...  ch1.send(ch2)
...  ch2.send("Hello")
...
>>> def b():
...  ch3 = ch1.receive()
...  print ch3.receive()
...
>>> stackless.tasklet(a)()
<stackless.tasklet object at 0x01C6FCB0>
>>> stackless.tasklet(b)()
<stackless.tasklet object at 0x01C6FAB0>
>>> stackless.run()
Hello
Matt Schmidt
+2  A: 

Channels send normal Python references so the data you send (channel, string, whatever) is exactly what is received.

One example of sending a channel over a channel is when you use a tasklet as a service, that is, a tasklet listens on a channel for requests, does work, and returns the result. The request needs to include the data for the work and the return channel for the result, so that the result goes to the requestor.

Here's an extreme example I developed for my Stackless talk at PyCon a few years ago. This creates a new tasklet for each function call so I can use a recursive implementation of factorial which doesn't need to worry about Python's stack limit. I allocate a tasklet for each call and it gets the return channel for the result.

import stackless 

def call_wrapper(f, args, kwargs, result_ch): 
    result_ch.send(f(*args, **kwargs)) 
    # ... should also catch and forward exceptions ... 

def call(f, *args, **kwargs): 
    result_ch = stackless.channel() 
    stackless.tasklet(call_wrapper)(f, args, kwargs, result_ch) 
    return result_ch.receive() 

def factorial(n): 
    if n <= 1: 
        return 1 
    return n * call(factorial, n-1) 

print "5! =", factorial(5) 
print "1000! / 998! =", factorial(1000)/factorial(998)

The output is:

5! = 120 
1000! / 998! = 999000

I have a few other examples of sending channels over channels in my presentation. It's a common thing in Stackless.

Andrew Dalke