<div dir="auto"><div><div class="gmail_extra"><div class="gmail_quote">On Sep 13, 2017 9:01 PM, "Nick Coghlan" <<a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a>> wrote:<br type="attribution"><blockquote class="m_1386731402657492592quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="m_1386731402657492592quoted-text">On 14 September 2017 at 11:44, Eric Snow <<a href="mailto:ericsnowcurrently@gmail.com" target="_blank">ericsnowcurrently@gmail.com</a>> wrote:<br></div><div class="m_1386731402657492592quoted-text">
>    send(obj):<br>
><br>
>        Send the object to the receiving end of the channel.  Wait until<br>
>        the object is received.  If the channel does not support the<br>
>        object then TypeError is raised.  Currently only bytes are<br>
>        supported.  If the channel has been closed then EOFError is<br>
>        raised.<br>
<br>
</div>I still expect any form of object sharing to hinder your<br>
per-interpreter GIL efforts, so restricting the initial implementation<br>
to memoryview-only seems more future-proof to me.<br></blockquote></div></div></div><div dir="auto"><br></div><div dir="auto">I don't get it. With bytes, you can either share objects or copy them and the user can't tell the difference, so you can change your mind later if you want. But memoryviews require some kind of cross-interpreter strong reference to keep the underlying buffer object alive. So if you want to minimize object sharing, surely bytes are more future-proof.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="m_1386731402657492592quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="m_1386731402657492592quoted-text"><br>
> Handling an exception<br>
> ---------------------<br>
><br>
> ::<br>
><br>
>    interp = interpreters.create()<br>
>    try:<br>
>        interp.run("""if True:<br>
>            raise KeyError<br>
>            """)<br>
>    except KeyError:<br>
>        print("got the error from the subinterpreter")<br>
<br>
</div>As with the message passing through channels, I think you'll really<br>
want to minimise any kind of implicit object sharing that may<br>
interfere with future efforts to make the GIL truly an *interpreter*<br>
lock, rather than the global process lock that it is currently.<br>
<br>
One possible way to approach that would be to make the low level run()<br>
API a more Go-style API rather than a Python-style one, and have it<br>
return a (result, err) 2-tuple. "err.raise()" would then translate the<br>
foreign interpreter's exception into a local interpreter exception,<br>
but the *traceback* for that exception would be entirely within the<br>
current interpreter.<br></blockquote></div></div></div><div dir="auto"><br></div><div dir="auto">It would also be reasonable to simply not return any value/exception from run() at all, or maybe just a bool for whether there was an unhandled exception. Any high level API is going to be injecting code on both sides of the interpreter boundary anyway, so it can do whatever exception and traceback translation it wants to.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="m_1386731402657492592quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="m_1386731402657492592quoted-text"><br>
> Reseting __main__<br>
> -----------------<br>
><br>
> As proposed, every call to ``Interpreter.run()`` will execute in the<br>
> namespace of the interpreter's existing ``__main__`` module.  This means<br>
> that data persists there between ``run()`` calls.  Sometimes this isn't<br>
> desireable and you want to execute in a fresh ``__main__``.  Also,<br>
> you don't necessarily want to leak objects there that you aren't using<br>
> any more.<br>
><br>
> Solutions include:<br>
><br>
> * a ``create()`` arg to indicate resetting ``__main__`` after each<br>
>   ``run`` call<br>
> * an ``Interpreter.reset_main`` flag to support opting in or out<br>
>   after the fact<br>
> * an ``Interpreter.reset_main()`` method to opt in when desired<br>
><br>
> This isn't a critical feature initially.  It can wait until later<br>
> if desirable.<br>
<br>
</div>I was going to note that you can already do this:<br>
<br>
    interp.run("globals().clear()"<wbr>)<br>
<br>
However, that turns out to clear *too* much, since it also clobbers<br>
all the __dunder__ attributes that the interpreter needs in a code<br>
execution environment.<br>
<br>
Either way, if you added this, I think it would make more sense as an<br>
"importlib.util.reset_globals(<wbr>)" operation, rather than have it be<br>
something specific to subinterpreters.<br></blockquote></div></div></div><div dir="auto"><br></div><div dir="auto">This is another point where the API could reasonably say that if you want clean namespaces then you should do that yourself (e.g. by setting up your own globals dict and using it to execute any post-bootstrap code).</div><div dir="auto"><br></div><div dir="auto">-n</div></div>