<div dir="ltr"><div><div class="gmail_extra"><div class="gmail_quote">On 18 October 2017 at 16:25, Ethan Furman <span dir="ltr"><<a href="mailto:ethan@stoneleaf.us" target="_blank">ethan@stoneleaf.us</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 10/17/2017 09:40 PM, Nick Coghlan wrote:<span class="gmail-"></span><span class="gmail-"></span><br><span class="gmail-"></span><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="gmail-">
At the Python API layer, we don't expose the ability to switch explicitly to another thread state while remaining within<br>
the current function. Instead, we only offer two options: starting a new thread, and waiting for a thread to finish<br>
execution. The lifecycle of the thread local storage is then intrinsically linked to the lifecycle of the thread it<br>
belongs to.<br>
</span></blockquote>
<br>
I seem to remember mention about frameworks being able to modify contexts for various tasks/coroutines; if the framework cannot create and switch to a new context how will it set them up?  Or did I misunderstand?</blockquote><div><br></div>That's what Context.run() will handle.</div><div class="gmail_quote"><br></div><div class="gmail_quote">From a usage perspective, what Yury and I are suggesting is that switching execution to a new context should always implicitly switch back when the called operation returns:</div><div class="gmail_quote"><br></div><div class="gmail_quote">    def run_in_isolated_ec(operation):<br></div><div class="gmail_quote">        ec = contextvars.new_context()</div><div class="gmail_quote">        return ec.run(operation)</div><div class="gmail_quote"><br></div><div class="gmail_quote">That's safe and simple to use, and integrates nicely with the APIs for resuming coroutines (next(cr), cr.__next__(), cr.send(), cr.throw()).<br></div><div class="gmail_quote"><br></div><div class="gmail_quote">By contrast, exposing set_ctx() directly puts the responsibility for reverting the active context back to the initial one on the caller:</div><div class="gmail_quote"><br></div><div class="gmail_quote"><div class="gmail_quote">    def run_in_isolated_ec(operation):<br></div>        ec = contextvars.new_context()</div><div class="gmail_quote">        initial_ec = contextvar.get_ctx()<br></div><div class="gmail_quote">        contextvars.set_ctx(ec)</div><div class="gmail_quote">        try:<br></div><div class="gmail_quote">            return operation()</div><div class="gmail_quote">        finally:<br></div><div class="gmail_quote"><div class="gmail_quote">            # What happens if we forget to revert back to the previous context here?<br></div>            contextvars.set_ctx(initial_ec)</div></div><div class="gmail_extra"><br></div><div class="gmail_extra">While the contextvars implementation is going to need a context switching capability like that internally in order to implement ec.run() (just as the threading implementation's C API includes PyThreadState_Swap), we don't currently have a use case for exposing it as a Python level API.</div><div class="gmail_extra"><br></div><div class="gmail_extra">And if we don't expose an API that allows it, then we can delay specifying what effect the following code should have all the calling function or coroutine (or whether it's a runtime error):</div><div class="gmail_extra"><br></div><div class="gmail_extra"><div class="gmail_quote"><div class="gmail_quote">    def buggy_run_in_isolated_ec(operation):<br></div>        ec = contextvars.new_context()</div>        contextvars.set_ctx(ec)</div><div class="gmail_extra">        return operation()</div><div class="gmail_extra">        # Oops, forgot to revert the active context to the one we were called with<br></div><br></div>So if we start out only exposing "Context.run()" at the Python layer (covering all currently known use cases), then any subsequent addition of an in-place context switching API can be guided by specific examples of situations where Context.run() isn't sufficient.<br><div><br><div class="gmail_extra">Cheers,</div><div class="gmail_extra">Nick.<br clear="all"></div><div class="gmail_extra"><br>-- <br><div class="gmail_signature">Nick Coghlan   |   <a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a>   |   Brisbane, Australia</div>
</div></div></div>