Jason Tackaberry wrote:
> 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,


Thanks Jason, it does help. I was under the impression that coroutines
were mainly used for cooperative multitasking and doing things in the
background where the result of the calls were not important.

Duncan

------------------------------------------------------------------------------
This SF.net email is sponsored by:
High Quality Requirements in a Collaborative Environment.
Download a free trial of Rational Requirements Composer Now!
http://p.sf.net/sfu/www-ibm-com
_______________________________________________
Freevo-devel mailing list
Freevo-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freevo-devel

Reply via email to