[Python-ideas] Async context managers and iterators with tulip

Geert Jansen geertj at gmail.com
Sun Dec 23 12:06:31 CET 2012


On Sat, Dec 22, 2012 at 10:14 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:

[...]
> We'd be heading even further down the path of
> two-languages-for-the-price-of-one if we did that, though (by which I
> mean the fact that async code and synchronous code exist in parallel
> universes - one, more familiar one, where the ability to block is
> assumed, as is the fact that any operation may give concurrent code
> the chance to execute, and the universe of Twisted, tulip, et al,
> where possible suspension points are required to be explicitly marked
> in the function where they occur).

The two languages/parallel universes (sync and asyc) is a big concern
IMHO. I looked at a greenlet based program that I'm writing and i'm
using call stacks that are 10 deep or so. I would need to change all
these layers from the scheduler down to use yield-from to make my
program async.

The higher levels are typically application specific and could decide
to either be sync or async. For the lower levels (e.g. transports and
protocols): those are typically library code and you'd need two
versions. The latter can amount to quite a bit of duplication: there's
a lot of protocol code currently in the standard library.

I wonder if the greenlet idea was thrown out too early. If I
understand the discussion correctly, the #1 disadvantage that was
identified is that calling code does not know if called code will
switch or not. Therefore it doesn't know whether to lock, and where.

What about the following (straw man) approach to fix that issue using
greenlets: functions can state if they are safe with regards to
switching using a decorator. The default is off (non-safe). When at
some point in the call graph you need to switch, you only to this if
all frames starting from the current one up to the scheduler are
async-safe. This should be achievable without any language changes.

Usually the upper layers in a concurrent program are connection
handlers. These can be marked safe quite easily as they usually only
use local stated tied to the connection and are not called from other
connections. Any code that they call would need to be explicitly
marked async-safe otherwise it could block.

I think the straw man above is identical to the current yield-from
approach in safety because there is no automatic asynchronicity.

However, this approach it has the benefit that there can be one
implementation of lower layers (protocols and transports) that
supports both sync and async, and higher layers can use the natural
calling syntax that they are currently used to. Also making a program
async can be an incremental process, and you could use e.g. a
sys.settrace() handler to identify spots where safe code calls into
unsafe code.

Regards,
Geert



More information about the Python-ideas mailing list