[Python-Dev] PEP 550 v4: coroutine policy

Yury Selivanov yselivanov.ml at gmail.com
Tue Aug 29 16:20:21 EDT 2017


On Tue, Aug 29, 2017 at 4:10 PM, Antoine Pitrou <antoine at python.org> wrote:
[..]
>> "await bar()" and "await wait_for(bar())" are actually quite
>> different.  Let me illustrate with an example:
>>
>>     b1 = bar()
>>     # bar() is not running yet
>>     await b1
>>
>>     b2 = wait_for(bar())
>>     # bar() was wrapped into a Task and is being running right now
>>     await b2
>>
>> Usually this difference is subtle, but in asyncio it's perfectly fine
>> to never await on b2, just let it run until it completes.  If you
>> don't "await b1" -- b1 simply will never run.
>
> Perhaps... But still, why doesn't bar() inherit the LC *at the point
> where it was instantiated* (i.e. foo()'s LC in the examples)?  The fact
> that it's *later* passed to wait_for() shouldn't matter, right?  Or
> should it?

bar() will inherit the lookup chain.  Two examples:

1)

   gvar = new_context_var()
   var = new_context_var()

   async def bar():
       # EC = [current_thread_LC_copy, Task_foo_LC]

       var.set(42)
       assert gvar.get() == 'aaaa'

   async def foo():
       # EC = [current_thread_LC_copy, Task_foo_LC]

       gvar.set('aaaa')
       await bar()
       assert var.get() == 42   # with previous PEP 550 semantics
       assert gvar.get() == 'aaaa'

   # EC = [current_thread_LC]
   run_until_complete(foo())   # Task_foo

2)

   gvar = new_context_var()
   var = new_context_var()

   async def bar():
       # EC = [current_thread_LC_copy, Task_foo_LC_copy, Task_wait_for_LC]

       var.set(42)
       assert gvar.get() == 'aaaa'

   async def foo():
       # EC = [current_thread_LC_copy, Task_foo_LC]

       await wait_for(bar(), 1)   # bar() is wrapped into
Task_wait_for implicitly

       assert gvar.get() == 'aaaa'   # OK
       assert var.get() == 42  # AssertionError !!!

   # EC = [current_thread_LC]
   run_until_complete(foo())   # Task_foo

The key difference:

In example (1), bar() will have the LC of the Task that runs foo().
Both "foo()" and "bar()" will *share* the same LC.  That's why foo()
will see changes made in bar().

In example (2), bar() will have the LC of wait_for() task, and foo()
will have a different LC.

Yury


More information about the Python-Dev mailing list