[Python-Dev] Timeout for PEP 550 / Execution Context discussion

Guido van Rossum guido at python.org
Tue Oct 17 11:51:38 EDT 2017


On Mon, Oct 16, 2017 at 10:02 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:

> On 17 October 2017 at 14:31, Guido van Rossum <guido at python.org> wrote:
>
>> No, that version just defers to magic in ContextVar.get/set, whereas what
>> I'd like to see is that the latter are just implemented in terms of
>> manipulating the mapping directly. The only operations for which speed
>> matters would be __getitem__ and __setitem__; most other methods just defer
>> to those. __delitem__ must also be a primitive, as must __iter__ and
>> __len__ -- but those don't need to be as speedy (however __delitem__ must
>> really work!).
>>
>
> To have the mapping API at the base of the design, we'd want to go back to
> using the ContextKey version of the API as the core primitive (to ensure we
> don't get name conflicts between different modules and packages), and then
> have ContextVar be a convenience wrapper that always accesses the currently
> active context:
>
>     class ContextKey:
>         ...
>     class ExecutionContext:
>         ...
>
>     class ContextVar:
>         def __init__(self, name):
>             self._key = ContextKey(name)
>
>         def get(self):
>             return get_execution_context()[self._key]
>
>         def set(self, value):
>             get_execution_context()[self._key] = value
>
>         def delete(self, value):
>             del get_execution_context()[self._key]
>

Why would we need this extra layer? I would assume that the key can just be
the ContextVar object itself, e.g.

    return get_execution_context()[self]

or

    get_execution_context()[self] = value


> While I'd defer to Yury on the technical feasibility, I'd expect that
> version could probably be made to work *if* you were amenable to some of
> the mapping methods on the execution context raising RuntimeError in order
> to avoid locking ourselves in to particular design decisions before we're
> ready to make them.
>
> The reason I say that is because one of the biggest future-proofing
> concerns when it comes to exposing a mapping as the lowest API layer is
> that it makes the following code pattern possible:
>
>     ec = get_execution_context()
>     # Change to a different execution context
>     ec[key] = new_value
>
> The appropriate semantics for that case (modifying a context that isn't
> the currently active one) are *really* unclear, which is why PEP 550
> structures the API to prevent it (context variables can only manipulate the
> active context, not arbitrary contexts).
>

But why on earth would you want to prevent that? If there's some caching
involved that I have overlooked (another problem with the complexity of the
design, or perhaps the explanation), couldn't mutating the non-context
simply set a dirty bit to ensure that if it ever gets made the current
context again the cache must be considered invalidated?


> However, even with a mapping at the lowest layer, a similar API constraint
> could still be introduced via a runtime guard in the mutation methods:
>
>     if get_execution_context() is not self:
>         raise RuntimeError("Cannot modify an inactive execution context")
>
> That way, to actually mutate a different context, you'd still have to
> switch contexts, just as you have to switch threads in C if you want to
> modify another thread's thread specific storage.
>

But that sounds really perverse. If anything, modifying an EC that's not
any thread's current context should be *simpler* than modifying the current
context. (I'm okay with a prohibition on modifying another *thread's*
current context.)

-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20171017/5997feb7/attachment.html>


More information about the Python-Dev mailing list