On Thu, 2009-04-02 at 18:09 +0200, Duncan Webb wrote:
> This is an example of making two rpc calls in a coroutine; the result of
> the coroutine is the result of the last rpc call. Error handling was not
> implemented in this example.

Ok, so RPC calls return InProgress objects that finish when the rpc
completes.  So you yield both calls, and then finally yield the result
of the last call:

        @kaa.coroutine()
        def func(remote):
           yield remote.rpc('foo')
           result = yield remote.rpc('bar')
           yield result

In the above (which uses Python 2.5 syntax in which the yield call can
return a value), the sequence happens like so:

     1. func() is entered; remote is an RPC Channel
     2. The 'foo' RPC call is marshaled and queued for delivery to the
        remote end.  remote.rpc() returns an InProgress, which is
        yielded by the coroutine func().
     3. The coroutine is resumed once the rpc 'foo' completes.
     4. Now the 'bar' RPC call is marshaled and queued for delivery to
        the remote end.  The coroutine func() yields the InProgress for
        this new rpc call.
     5. The coroutine is resumed once the rpc 'bar' completes.  The
        result of that rpc is "returned" into the coroutine via the
        yield, which is assigned to the result variable.
     6. We yield the result value from the coroutine, thereby finishing
        the coroutine.

The last two lines could be written as:

   yield (yield remote.rpc('bar'))

But it is probably best to leave it as two separate lines because it's
more readable.



> of coroutines. It is quite tricky to find suitable places in freevo-1
> that make a difference to the application. I had to remove one of the
> few callback methods in the tvguide as it was making the guide behave badly.

Part of that may be that you don't have an intuitive grasp on coroutines
yet, so it's not really clear at all where you could use them.  A second
reason is that if you design your application to use signals and
callbacks from the start, coroutines don't really fit in very well.
Think of coroutines as an alternative approach to a sequence of signals
and callbacks.


> > Whenever you yield a non-InProgress result from a coroutine, the
> > coroutine is finished with that result and never reentered.
> 
> I'm not 100% sure that I get this. Do you mean yielding anything other
> than the in-progress object causes the coroutine to finish there (like a
> return in a method)?

That's right.  One further exception to that rule is kaa.NotFinished,
which is a simple way for you to basically time slice a coroutine.
Think of it as cooperative multitasking.

This is documented at https://urandom.ca/~tack/kaa/async/coroutines.html


> I'll read through this as it has changed since the earlier versions of
> the kaa.async package.

Quite a bit, yeah.


> What would be nice is an example of coroutines in action that shows why
> someone would want to use them over threads or synchronous code.

In the above URL I try to explain some of the reasons you would use
coroutines.  I provide an example of connecting to a socket and fetching
a web page using a single coroutine:

        @kaa.coroutine()
        def fetch_page(host):
            """
            Fetches / from the given host on port 80.
            """
            socket = kaa.Socket()
            # Socket.connect() is implemented as a thread
            yield socket.connect((host, 80))
            # Socket.read() and write() are implemented as single-thread async 
I/O.
            yield socket.write('GET / HTTP/1.1\n\n')
            print (yield socket.read())

But to drive the point home, I should also provide the code that does
the same thing only _without_ a coroutine, by using callbacks and
connecting to each step:

        def fetch_page(host):
            socket = kaa.Socket()
            socket.connect((host, 80)).connect(finished_connect, socket)
        
        def finished_connect(result, socket):
            socket.write('GET / HTTP/1.1\n\n').connect(finished_write, socket)
        
        def finished_write(len, socket):
            socket.read().connect(finished_read)
        
        def finished_read(data):
            print data


The above is functionally equivalent to the coroutine.  But you can see
which code is easier to follow.

Hope that helps,
Jason.


------------------------------------------------------------------------------
_______________________________________________
Freevo-devel mailing list
Freevo-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freevo-devel

Reply via email to