[Python-Dev] Re: [Stackless] comments on PEP 219
Gordon McMillan
gmcm@hypernet.com
Tue, 13 Mar 2001 17:16:24 -0500
[Jeremy]
> >> If a programmer uses a library implement via coroutines, can
> she >> call library methods from an __xxx__ method?
>
> GMcM> Certain situations won't work, but you knew that.
>
> I expected that some won't work, but no one seems willing to tell
> me exactly which ones will and which ones won't. Should the
> caveat in the documentation say "avoid using certain __xxx__
> methods" <0.9 wink>.
Within an __xxx__ method, you cannot *use* a coroutine not
created in that method. That is true in current Stackless and
will be true in Stack-lite. The presence of "library" in the
question is a distraction.
I guess if you think of a coroutine as just another kind of
callable object, this looks like a strong limitation. But you
don't find yourself thinking of threads as plain old callable
objects, do you? In a threaded program, no matter how
carefully designed, there is a lot of thread detritus lying
around. If you don't stay concious of the transfers of control
that may happen, you will screw up.
Despite the limitation on using coroutines in magic methods,
coroutines have an advantage in that tranfers of control only
happen when you want them to. So avoiding unwanted
transfers of control is vastly easier.
> >> Can coroutines or microthreads co-exist with callbacks
> invoked by >> C extensions?
>
> GMcM> Again, in certain situations it won't work. Again, you
> knew GMcM> that.
>
> Wasn't sure.
It's exactly the same situation.
> >> Can a program do any microthread IO in an __call__ method?
>
> GMcM> Considering you know the answer to that one too, you
> could've GMcM> phrased it as a parsable question.
>
> Do I know the answer? I assume the answer is no, but I don't
> feel very certain.
What is "microthreaded IO"? Probably the attempt to yield
control if the IO operation would block. Would doing that
inside __call__ work with microthreads? No.
It's not my decision over whether this particular situation
needs to be documented. Somtime between the 2nd and 5th
times the programmer encounters this exception, they'll say
"Oh phooey, I can't do this in __call__, I need an explicit
method instead." Python has never claimed that __xxx__
methods are safe as milk. Quite the contrary.
> >> If any of these are the sort "in theory" problems that the
> PEP >> alludes to, then we need a full spec for what is and is
> not >> allowed. It doesn't make sense to tell programmers to
> follow >> unspecified "reasonable" programming practices.
>
> GMcM> That's easy. In a nested invocation of the Python
> interpreter, GMcM> you can't use a coroutine created in an
> outer interpreter.
>
> Can we define these situations in a way that doesn't appeal to
> the interpreter implementation?
No, because it's implementation dependent.
> If not, can we at least come up
> with a list of what will and will not work at the python level?
Does Python attempt to catalogue all the ways you can screw
up using magic methods? Using threads? How 'bout the
metaclass hook? Even stronger, do we catalogue all the ways
that an end-user-programmer can get bit by using a library
written by someone else that makes use of these facilities?
> GMcM> In the Python 2 documentation, there are 6 caveats listed
> in GMcM> the thread module. That's a couple order of magnitudes
> GMcM> different from the actual number of ways you can screw up
> GMcM> using the thread module.
>
> The caveats for the thread module seem like pretty minor stuff to
> me. If you are writing a threaded application, don't expect code
> to continue running after the main thread has exited.
Well, the thread caveats don't mention the consequences of
starting and running a thread within an __init__ method.
> The caveats for microthreads seems to cover a vast swath of
> territory: The use of libraries or extension modules that involve
> callbacks or instances with __xxx__ methods may lead to
> application failure.
While your statement is true on the face of it, it is very
misleading. Things will only fall apart when you code an
__xxx__ method or callback that uses a pre-existing coroutine
(or does a uthread swap). You can very easily get in trouble
right now with threads and callbacks. But the real point is that
it is *you* the programmer trying to do something that won't
work (and, BTW, getting notified right away), not some library
pulling a fast one on you. (Yes, the library could make things
very hard for you, but that's nothing new.)
Application programmers do not need magic methods. Ever.
They are very handy for people creating libraries for application
programmers to use, but we already presume (naively) that
these people know what they're doing.
> I worry about it becomes it doesn't sound
> very modular. The use of coroutines in one library means I can't
> use that library in certain special cases in my own code.
With a little familiarity, you'll find that coroutines are a good
deal more modular than threads.
In order for that library to violate your expectations, that library
must be concious of multiple coroutines (otherwise, it's just a
plain stackfull call / return). It must have kept a coroutine from
some other call, or had you pass one in. So you (if at all
cluefull <wink>) will be concious that something is going on
here.
The issue is the same as if you used a framework which used
real threads, but never documented anything about the
threads. You code callbacks that naively and independently
mutate a global collection. Do you blame Python?
> I'm sorry if I sound grumpy, but I feel like I can't get a
> straight answer despite several attempts. At some level, it's
> fine to say that there are some corner cases that won't work well
> with microthreads or coroutines implemented on top of stackless
> python. But I think the PEP should discuss the details. I've
> never written in an application that uses stackless-based
> microthreads or coroutines so I don't feel confident in my
> judgement of the situation.
And where on the fearful to confident scale was the Jeremy
just getting introduced to threads?
> Which gets back to Bernd's original question:
>
> GMcM> > BR> """ Don't use classes and libraries that use
> classes when GMcM> > BR> IO in microthreaded programs! """
> GMcM> > GMcM> > BR> which might indeed be a problem. Am I
> overlooking something GMcM> > BR> fundamental here?
>
> and the synopsis of your answer:
>
> GMcM> Synopsis of my reply: this is more a problem with
> uthreads GMcM> than coroutines. In any (real) thread, you're
> limited to dealing GMcM> with one non-blocking IO technique
> (eg, select) without going GMcM> into a busy loop. If you're
> dedicating a (real) thread to select, it GMcM> makes more sense
> to use coroutines than uthreads.
>
> I don't understand how this addresses the question, but perhaps I
> haven't seen your reply yet. Mail gets through to python-dev and
> stackless at different rates.
Coroutines only swap voluntarily. It's very obvious where these
transfers of control take place hence simple to control when
they take place. My suspicion is that most people use
uthreads because they use a familiar model. Not many people
are used to coroutines, but many situations would be more
profitably approached with coroutines than uthreads.
- Gordon