[Python-ideas] Late to the async party (PEP 3156)

Guido van Rossum guido at python.org
Sun Dec 16 06:37:15 CET 2012


Hi Jason,

I don't think you've missed anything. I had actually planned to keep
PEP 3156 unpublished for a bit longer, since I'm not done writing the
reference implementation -- I'm sure that many of the issues currently
marked open or TBD will be resolved that way. There hasn't been any
public discussion since the last threads on python-ideas some weeks
ago -- however I've met in person with some Twisted folks and
exchanged private emails with some other interested parties.

You've also correctly noticed that the PEP is weakest in the area of
cancellation (and timeouts aren't even mentioned in the current
draft). I'm glad you have some experience in this area, and I'll try
to study your solutions and suggestions in more detail soon.

For integration with threads, I'm thinking that the PEP currently has
the minimum needed with wrap_future() and run_in_executor() -- but
I'll read your link on threads and see what I may be missing.

(More later, but I don't want you to think you posted into a black hole!)

--Guido

On Sat, Dec 15, 2012 at 5:36 PM, Jason Tackaberry <tack at urandom.ca> wrote:
> Hi python-ideas,
>
> I've been somewhat living under a rock for the past few months and
> consequently I missed the ideal window of opportunity to weigh in on the
> async discussions this fall that culminated into PEP 3156.
>
> I've been reading through those discussions in the archives.  I've not
> finished digesting it all, and I'm somewhat torn in that I feel I should
> shut up until I read everything to date so as not to decrease the SNR, but
> on the other hand, knowing myself, I strongly suspect this would result in
> my never speaking up.  And so, at risk of lowering the SNR ...
>
> First let me say that PEP 3156 makes me very, very happy.
>
> Over the past few years I've been exploring these very ideas with a
> little-used library called Kaa.  I'm not offering it up as a paragon of
> proper async library design, but I wanted to share some of my experiences in
> case they could be useful to the PEP.
>
>     https://github.com/freevo/kaa-base/
>     http://api.freevo.org/kaa-base/
>
> It does seem like many similar design choices were made.  In particular, I'm
> happy that an explicit yield will be used rather than the greenlet style of
> implicit suspension/reentry.   Even after I've been using them for years,
> coroutines often feel like a form of magic, and an explicit yield is more
> aligned with the principle of least surprise.
>
> With Kaa, our future-style object is called an InProgress (so forgive the
> differing terminology in the remainder of this post):
>
>     http://api.freevo.org/kaa-base/async/inprogress.html
>
> A couple properties of InProgress objects that I've found have practical
> value:
>
> they can be aborted, which raises a special InProgressAborted inside the
> coroutine function so it can perform cleanup actions
>
> what makes this tricky is the question of what to do to any currently
> yielded tasks?  If A yields B and A is aborted, should B be aborted?  What
> if the same B task is being yielded by C?  Should C also be aborted, even if
> it's considered a sibling of A?  (For example, suppose B is a task that is
> refreshing some common cache that both A and C want to make sure is
> up-to-date before they move on.)
> if the decision is B should be aborted, then within A, 'yield B' will raise
> an exception because A is aborted, but 'yield B' within C will raise because
> B was aborted.  So there needs to be some mechanism to distinguish between
> these cases.  (My approach was to have an origin attribute on the
> exception.)
> if A yields B, it may want to prevent B from being aborted if A is aborted.
> (My approach was to have a noabort() method in InProgress objects to return
> a new, unabortable InProgress object that A can then yield.)
> alternatively, the saner implementation may be to do nothing to B when A is
> aborted and require A catch InProgressAborted and explicitly abort B if
> that's the desired behaviour
> discussion in the PEP on cancellation has some TBDs so perhaps the above
> will be food for thought
>
> they have a timeout() method, which returns a new InProgress object
> representing the task that will abort when the timeout elapses if the task
> doesn't finish
>
> it's noteworthy that timeout() returns a new InProgress and the original
> task continues on even if the timeout occurs -- by default that is, unless
> you do timeout(abort=True)
> I didn't see much discussion in the PEP on timeouts, but I think this is an
> important feature that should be standardized
>
>
> Coroutines in Kaa use "yield" rather than "yield from" but the general
> approach looks very similar to what's been proposed:
>
>     http://api.freevo.org/kaa-base/async/coroutines.html
>
> The @coroutine decorator causes the decorated function to return an
> InProgress.  Coroutines can of course yield other coroutines, but, more
> fundamentally, anything else that returns an InProgress object, which could
> be a @threaded function, or even an ordinary function that explicitly
> creates and returns an InProgress object.
>
> There are some features of Kaa's implementation that could be worth
> considering:
>
> it is possible to yield a special object (called NotFinished) that allows a
> coroutine to "time slice" as a form of cooperative multitasking
> coroutines can have certain policies that control invocation behaviour.  The
> most obvious ones to describe are POLICY_SYNCHRONIZED which ensures that
> multiple invocations of the same coroutine are serialized, and
> POLICY_SINGLETON which effectively ignores subsequent invocations if it's
> already running
> it is possible to have a special progress object passed into the coroutine
> function so that the coroutine's progress can be communicated to an outside
> observer
>
>
> Once you've standardized on a way to manage the lifecycle of an in-progress
> asynchronous task, threads are a natural extension:
>
>     http://api.freevo.org/kaa-base/async/threads.html
>
> The important element here is that @threaded decorated functions can be
> yielded by coroutines.  This means that truly blocking tasks can be wrapped
> in a thread but invocation from a coroutine is identical to any other
> coroutine.  Consequently, a threaded task could later be implemented as a
> coroutine (or more generally via event loop hooks) without any API changes.
>
> I think I'll stop here.  There's plenty more definition, discussion, and
> examples in the links above.  Hopefully some ideas can be salvaged for PEP
> 3156, but even if that's not the case, I'll be happy to know they were
> considered and rejected rather than not considered at all.
>
> Cheers,
> Jason.
>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> http://mail.python.org/mailman/listinfo/python-ideas
>



-- 
--Guido van Rossum (python.org/~guido)



More information about the Python-ideas mailing list