Skip to content.

logo Stackless Python


Personal tools
Views

History for Channels

typo
changed:
-
In [Stackless], a *channel* object is used for bidirectional communication between [tasklets]. 
Channels do not contain data themselves, but only transmit python objects between a sender and 
the next tasklet in the receiving queue.

By sending on a channel, a tasklet that is waiting to receive on that channel is resumed. If 
there is no waiting receiver, the sender is suspended (blocked) into the channel's queue.  By 
receiving from a channel, a tasklet that is waiting to send on that channel is resumed. If there 
is no waiting sender, the receiver is suspended into the channel's queue.

Multiple tasklets sending or recieving on the same channel are kept track of in the channel's queue.
The number of tasklets in the queue can be found using the channel's "balance" property.  The value 
corresponds to the number of waiting tasklets.  A positive value indicates a queue of tasklets 
waiting to send; receiving tasklets are signaled by a negative value, and a value of zero indicates 
an idle channel.

Following are basic channel examples.  For more advanced derviations from the channels, please see [ChannelExamples].

Creating a stackless.channel
----------------------------
The simplest way to create a stackless channel is by calling the class stackless.channel::

    import stackless
    ch=stackless.channel()

Sending and receiving from a channel
------------------------------------
Now that we have a channel, we have to use it for something.  Lets say we want to send the value "foo" on our new channel.::

    import stackless
    ch=stackless.channel()
    ch.send("foo")

Now please note that if we send through a channel that has nothing waiting to receive, we stop the current tasklet from running.  This includes the main tasklet so if we ran the code as is we would receive an error.

This brings us to the next step, getting data from a channel.  Getting data from a channel is almost exactly the same as sending it.  Lets say we want to get a value from our channel and print it.::

    import stackless
    
    ch=stackless.channel()
    print ch.receive()
    
Again, the same caveat applies about receiving.  Since nothing is being sent on our channel, this code would wait forever for something to be sent.

In order to make this work, we will need to use tasklets.  For an explanation of them see the [Tasklets] page.  For now it suffices to say that a function created as a tasklet runs independently and thus if we use them we won't be getting errors.::

    import stackless

    def Sending(channel):
        print "sending"
        channel.send("foo")

    def Receiving(channel):
        print "receiving"
        print channel.receive()

    ch=stackless.channel()
    
    task=stackless.tasklet(Sending)(ch)
    task2=stackless.tasklet(Receiving)(ch)
    stackless.run()

When this code is run we get the following result::

    sending
    receiving
    foo

You can also send and receive sequences (iterators) over a channel.::

    import stackless

    def SendingSequence(channel, sequence):
        print "sending"
        channel.send_sequence(sequence)

    def ReceivingSequence(channel):
        for item in channel:
            print "receiving"
            print item

    ch=stackless.channel()
        
    task=stackless.tasklet(SendingSequence)(ch, ['a','b','c'])
    task2=stackless.tasklet(ReceivingSequence)(ch)
    stackless.run()     
 
When this code is run we get the following result::

    sending
    receiving
    a
    receiving
    b
    receiving
    c

At this point, task2 is still running, waiting on the channel for more items. To let it know that it's done, you have to send a StopIteration exception across the channel.::

    import stackless
    from exceptions import StopIteration

    def SendingSequence(channel, sequence):
        print "sending"
        channel.send_sequence(sequence)
        channel.send_exception(StopIteration)

    def ReceivingSequence(channel):
        for item in channel:
            print "receiving"
            print item
        print "done receiving"

    ch=stackless.channel()
        
    task=stackless.tasklet(SendingSequence)(ch, ['a','b','c'])
    task2=stackless.tasklet(ReceivingSequence)(ch)
    stackless.run()

And now it should output::

    sending
    receiving
    a
    receiving
    b
    receiving
    c
    done receiving

And that concludes sending and receiving via channels.

Channel Balance
---------------
In stackless, the balance of a channel is how many tasklets are waiting to send or receive on it.  When we first create a channel nothing is happening so the code::

    import stackless

    ch=stackless.channel()
    print "Channel balance is ",ch.balance

displays::

    Channel balance is 0

Now if we borrow our sending tasklet from above::

    import stackless

    def Sending(channel):
        print "sending"
        channel.send("foo")
    
    ch=stackless.channel()
    
    task=stackless.tasklet(Sending)(ch)
    stackless.run()

    print "Channel balance is ",ch.balance

We get the following result::

    sending
    Channel balance is 1

Which tells us that one tasklet is waiting to send.

If we use our receiving tasklet we will get the opposite result, so::

    import stackless

    def Receiving(channel):
        print "receiving"
        print channel.receive()
    
    ch=stackless.channel()
    
    task2=stackless.tasklet(Receiving)(ch)
    stackless.run()

    print "Channel balance is ",ch.balance

displays::

    receiving
    Channel balance is -1



From littldo Thu Apr 15 03:07:41 +0200 2004
From: littldo
Date: Thu, 15 Apr 2004 03:07:41 +0200
Subject: Q: What topologies are supported by Channels
Message-ID: <20040415030741+0200@www.stackless.com>

Is a channel a point-to-point connection or can other topologies be supported?

From warnes Sat Sep 3 06:09:43 +0200 2005
From: warnes
Date: Sat, 03 Sep 2005 06:09:43 +0200
Subject: Race condition in extension code?
Message-ID: <20050903060943+0200@www.stackless.com>

It looks to me like both Nonblocking Channel and Broadcast Channel contain a race condition if interrupted between checking the balance and performing the send/recieve. 

From rmtew Fri Dec 9 07:21:01 +0100 2005
From: rmtew
Date: Fri, 09 Dec 2005 07:21:01 +0100
Subject: Race condition
Message-ID: <20051209072101+0100@www.stackless.com>

Perhaps, but uncertainties like that are why I always use the cooperative scheduling of Stackless, rather than the preemptive scheduling.  In which case, there is no chance of a race condition.

From rmtew Fri Dec 9 07:23:46 +0100 2005
From: rmtew
Date: Fri, 09 Dec 2005 07:23:46 +0100
Subject: A: What topologies are supported by Channels
Message-ID: <20051209072346+0100@www.stackless.com>

The most common use of channels in my experience is point-to-point where a tasklet is stalled until another awakens by sending it a result.  But it is easy enough to build a queue on top of channels where multiple tasklets wait for a resource to load and then when it is loaded, the channel is sent to until all senders are removed.  Is this the sort of thing meant?

From garo Thu Mar 23 11:01:24 +0100 2006
From: garo
Date: Thu, 23 Mar 2006 11:01:24 +0100
Subject: Q: receive() and execution queue
Message-ID: <20060323110124+0100@www.stackless.com>

Does calling receive() remove the calling tasklet from the execution/runnable queue if the receive() blocks?

From BBuco Sat Apr 8 21:35:28 +0200 2006
From: BBuco
Date: Sat, 08 Apr 2006 21:35:28 +0200
Subject: A: receive() and execution queue 
Message-ID: <20060408213528+0200@www.stackless.com>

Yes, the tasklet is removed until it is unblocked when something is sent through that channel.
 

Powered by Plone