[Python-Dev] Obtaining stack-frames from co-routine objects

Ben Leslie benno at benno.id.au
Sat Jun 13 12:36:55 CEST 2015


On 13 June 2015 at 19:03, Guido van Rossum <guido at python.org> wrote:
> On Sat, Jun 13, 2015 at 12:22 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:
>>
>> On 13 June 2015 at 04:13, Guido van Rossum <guido at python.org> wrote:
>> > IOW I don't think that the problem here is that you haven't sufficiently
>> > motivated your use case -- you are asking for information that just
>> > isn't
>> > available. (Which is actually where you started the thread -- you can
>> > get to
>> > the frame of the coroutine but there's nowhere to go from that frame.)
>>
>> If I'm understanding Ben's request correctly, it isn't really the
>> stack trace that he's interested in (as you say, that specific
>> phrasing doesn't match the way coroutine suspension works), but rather
>> having visibility into the chain of control flow delegation for
>> currently suspended frames: what operation is the outermost frame
>> ultimately blocked *on*, and how did it get to the point of waiting
>> for that operation?
>>
>> At the moment, all of the coroutine and generator-iterator resumption
>> information is implicit in the frame state, so we can't externally
>> introspect the delegation of control flow in a case like Ben's
>> original example (for coroutines) or like this one for generators:
>>
>>     def g1():
>>         yield 42
>>
>>     def g2():
>>         yield from g1()
>>
>>     g = g2()
>>     next(g)
>>     # We can tell here that g is suspended
>>     # We can't tell that it delegated flow to a g1() instance
>>
>> I wonder if in 3.6 it might be possible to *add* some bookkeeping to
>> "await" and "yield from" expressions that provides external visibility
>> into the underlying iterable or coroutine that the generator-iterator
>> or coroutine has delegated flow control to. As an initial assessment,
>> the runtime cost would be:
>>
>> * an additional pointer added to generator/coroutine objects to track
>> control flow delegation
>> * setting that when suspending in "await" and "yield from" expressions
>> * clearing it when resuming in "await" and "yield from" expressions
>>
>> (This would be a read-only borrowed reference from a Python level
>> perspective, so it shouldn't be necessary to alter the reference count
>> - we'd just be aliasing the existing reference from the frame's
>> internal stack state)
>
>
> Ah, this makes sense. I think the object you're after is 'reciever' [sic] in
> the YIELD_FROM opcode implementation, right?

Right this is the exact book-keeping that I was originally referring to in
my previous emails (sorry for not making that more explicit earlier).
The 'reciever' is actually on the stack part of the co-routine's frame all
the time (i.e.: pointed to via f->f_stacktop).

So from my point of view the book-keeping is there (albeit somewhat
obscurely!), but the objects on the frame's stack aren't exposed via
the Python wrapping of PyFrameObject, (although could, I think, easily
be exposed). Once you get at the receiver object (which is another
co-routine) you can traverse down to the point the co-routine 'switched'.

Cheers,

Ben


More information about the Python-Dev mailing list