[Python-ideas] PEP 550 v2

Yury Selivanov yselivanov.ml at gmail.com
Wed Aug 16 12:55:55 EDT 2017


On Wed, Aug 16, 2017 at 12:51 PM, Yury Selivanov
<yselivanov.ml at gmail.com> wrote:
> On Wed, Aug 16, 2017 at 5:36 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:
>> On 16 August 2017 at 17:18, Nathaniel Smith <njs at pobox.com> wrote:
>> [Yury wrote]
> [..]
>>>>   * If ``coro.cr_local_context`` is an empty ``LocalContext`` object
>>>>     that ``coro`` was created with, the interpreter will set
>>>>     ``coro.cr_local_context`` to ``None``.
>>>
>>> I like all the ideas in this section, but this specific point feels a
>>> bit weird. Coroutine objects need a second hidden field somewhere to
>>> keep track of whether the object they end up with is the same one they
>>> were created with?
>>
>> It feels odd to me as well, and I'm wondering if we can actually
>> simplify this by saying:
>>
>> 1. Generator contexts (both sync and async) are isolated by default
>> (__local_context__ = LocalContext())
>> 2. Coroutine contexts are *not* isolated by default (__local_context__ = None)
>>
>> Running top level task coroutines in separate execution contexts then
>> becomes the responsibility of the event loop, which the PEP already
>> lists as a required change in 3rd party libraries to get this all to
>> work properly.
>
> This is an interesting twist, and I like it.
>
> This will change asyncio.Task from:
>
>     class Task:
>
>        def __init__(self, coro):
>            ...
>            self.exec_context = sys.get_execution_context()
>
>        def step():
>
>          sys.run_with_execution_context(self.coro.send)
>
>
> to:
>
>     class Task:
>
>        def __init__(self, coro):
>            ...
>            self.local_context = sys.new_local_context()
>
>        def step():
>
>          sys.run_with_local_context(self.local_context, self.coro.send)
>
> And we don't need ceval to do anything for "await", which means that
> with this approach we won't touch ceval.c at all.


And immediately after I hit "send" I realized that this is a bit more
complicated.

In order for Tasks to remember the full execution context of where
they were created, we need a new method that would allow to run with
*both* exec and local contexts:

    class Task:

       def __init__(self, coro):
           ...
           self.local_context = sys.new_local_context()
           self.exec_context = sys.get_execution_context()

       def step():

         sys.run_with_contexts(self.exec_context, self.local_context,
self.coro.send)

This is needed for the following PEP example to work properly:

    current_request = sys.new_context_item(description='request')

    async def child():
        print('current request:', repr(current_request.get()))

    async def handle_request(request):
        current_request.set(request)
        event_loop.create_task(child)

    run(top_coro())

See https://www.python.org/dev/peps/pep-0550/#tasks

Yury


More information about the Python-ideas mailing list