[Python-Dev] Slides from today's parallel/async Python talk

Trent Nelson trent at snakebite.org
Tue Mar 19 02:26:45 CET 2013


On Mon, Mar 18, 2013 at 05:27:33PM -0700, Christian Tismer wrote:
> Hi Trent,

    Hi Christian!  Thanks for taking the time to read my walls of text
    ;-)

> > So, the remaining challenge is preventing the use case alluded to
> > earlier where someone tries to modify an object that hasn't been "async
> > protected".  That's a bit harder.  The idea I've got in mind is to
> > instrument the main CPython ceval loop, such that we do these checks as
> > part of opcode processing.  That allows us to keep all the logic in the
> > one spot and not have to go hacking the internals of every single
> > object's C backend to ensure correctness.
> >
> > Now, that'll probably work to an extent.  I mean, after all, there are
> > opcodes for all the things we'd be interested in instrumenting,
> > LOAD_GLOBAL, STORE_GLOBAL, SETITEM etc.  What becomes challenging is
> > detecting arbitrary mutations via object calls, i.e. how do we know,
> > during the ceval loop, that foo.append(x) needs to be treated specially
> > if foo is a main-thread object and x is a parallel thread object?
> >
> > There may be no way to handle that *other* than hacking the internals of
> > each object, unfortunately.  So, the viability of this whole approach
> > may rest on whether or that's deemed as an acceptable tradeoff (a
> > necessary evil, even) to the Python developer community.
> 
> This is pretty much my concern:
> In order to make this waterproof, as required for CPython, you will quite
> likely have to do something on very many objects, and this is hard
> to chime into CPython.

    Actually, I think I was unnecessarily pessimistic here.  When I sent
    that follow-up mail with cross-references, I realized I'd forgotten
    the nitty gritty details of how I implemented the async protection
    support.

    It turns out I'd already started on protecting lists (or rather,
    PySequenceMethods), but decided to stop as the work I'd done on the
    PyMappingMethods was sufficient for my needs at the time.

    All I *really* want to do is raise an exception if a parallel object
    gets assigned to a main-thread container object (list/dict etc) that
    hasn't been "async protected".  (As opposed to now, where it'll
    either segfault or silently corrupt stuff, then segfault later.)

    I've already got all the infrastructure in place to test that (I use
    it extensively within pyparallel.c):

        Py_ISPY(obj)         - detect a main-thread object
        Py_ISPX(obj)         - detect a parallel-thread object
        Py_IS_PROTECTED(obj) - detect if a main-thread object has
                               been protected*

            [*]: actually, this isn't in a macro form right now, it's a
            cheeky inline:

                __inline
                char
                _protected(PyObject *obj)
                {
                    return (obj->px_flags & Py_PXFLAGS_RWLOCK);
                }

    As those macros are exposed in the public <Include/pyparallel.h>,
    they can be used in other parts of the code base.  So, it's just a
    matter of finding the points where an `lvalue = rvalue` takes place;
    where: ``Py_ISPY(lvalue) && Py_ISPX(rvalue)``.  Then a test to see
    if lvalue is protected; if not, raise an exception.  If so, then
    nothing else needs to be done.

    And there aren't that many places where this happens.  (It didn't
    take long to get the PyMappingMethods intercepts nailed down.)

    That's the idea anyway.  I need to get back to coding to see how it
    all plays out in practice.  "And there aren't many places where this
    happens" might be my famous last words.

> > If it's not, then it's unlikely this approach will ever see the light of
> > day in CPython.  If that turns out to be the case, then I see this
> > project taking the path that Stackless took (forking off and becoming a
> > separate interpreter).
> 
> We had that discussion quite often for Stackless, and I would love to find
> a solution that allows to add special versions and use cases to CPython
> in a way that avoids the forking as we did it.
> 
> It would be a nice thing if we could come up with a way to keep CPython
> in place, but to swap the interpreter out and replace it with a specialized
> version, if the application needs it. I wonder to what extent that would be
> possible.
> What I would like to achieve, after having given up on Stackless integration
> is a way to let it piggyback onto CPython that works like an extension
> module, although it hat effectively replace larger parts of the interpreter.
> I wonder if that might be the superior way to have more flexibility, 
> without forcing
> everything and all go into CPython.
> If we can make the interpreter somehow pluggable at runtime, a lot of issues
> would become much simpler.
> 
> >
> > There's nothing wrong with that; I am really excited about the
> > possibilities afforded by this approach, and I'm sure it will pique the
> > interest of commercial entities out there that have problems perfectly
> > suited to where this pattern excels (shared-nothing, highly concurrent),
> > much like the relationship that developed between Stackless and Eve
> > Online.
> >
> 
> What do you think: does it make sense to think of a framework that
> allows to replace the interpreter at runtime, without making normal
> CPython really slower?

    I think there may actually be some interest in what you're
    suggesting.  I had a chat with various other groups over PyCon that
    had some interesting things in the pipeline, and being able to call
    back out to CPython internals like you mentioned would be useful to
    them.

    I don't want to take my pyparallel work in that direction yet; I'm
    still hoping I can fix all the show stoppers and have the whole
    thing eligible for CPython inclusion one day ;-)  (So, I'm like you,
    10 years ago? :P)

    Regards,

        Trent.


More information about the Python-Dev mailing list