[PEAK] Reactor-driven microthreads
Phillip J. Eby
pje at telecommunity.com
Wed Dec 31 14:17:02 EST 2003
At 01:50 PM 12/31/03 -0500, Bob Ippolito wrote:
>On Dec 31, 2003, at 1:12 PM, Phillip J. Eby wrote:
>
>>At 12:12 PM 12/31/03 -0500, Bob Ippolito wrote:
>>>On Dec 31, 2003, at 12:22 AM, Phillip J. Eby wrote:
>>>
>>>>Hm. This seems like the first really good use case I've seen for
>>>>having a macro facility in Python, since it would allow us to spell
>>>>the yield+errorcheck combination with less boilerplate. Ah well.
>>>
>>>That, and "flattening" generators
>>>
>>>def someGenerator():
>>> for something in someOtherGenerator():
>>> yield something
>>>
>>>This gets really ugly after a while, but it happens a lot when you are
>>>doing "microthreads".
>>
>>Actually, the Thread class in my second post allows you to do:
>>
>>def someGenerator():
>> yield someOtherGenerator(); resume()
>>
>>Thread objects maintain an external "stack" of nested generators, so you
>>don't need to do this kind of passthru.
>
>That is the other way to do it, but I don't like that at all. It's not a
>general solution, I use this 'pattern' very often with or without a
>'scheduler' on the outside.
I'm a bit confused. Do you mean that you often need to yield the contents
of another generator often, or that you use
microthreading-without-a-scheduler often?
>I didn't write and I don't use twisted.flow so I have no idea, but I think
>that the code that I posted in the mailing list is somewhat roughly
>equivalent (in a same-concept-but-not-nearly-as-polished kind of way) to
>yours though... except it requires you to yield a particular kind of
>object from your iterable "microthread" and that object has your "resume"
>method. The only real thing about your implementation that I disagree
>with is this global resume function.
From my POV, 'resume()' is a macro that happens to be implemented as a
function. :)
I'd be interested in seeing the code you mention though; got an archive
URL? (I assume you're referring to the twisted mailing list.)
>Oh, and I disagree with the fact that you say "generators provide an ideal
>basis". Ideally, you'd be using Stackless Python.
No, ideally Python would be "stackless" in that sense. The fact that
there's a separate Stackless Python is what makes it less than
ideal. :) I meant, "an ideal basis, given the limitations of Python
2.2". The "given current Python" part is second nature to me because I
expect to be supporting CPython 2.2 in production through at least
mid-2004, so it doesn't occur to me to contemplate using anything else. :)
>In any case, I use code like this quite often with and without Twisted and
>agree that it helps in quite a few situations but in others you really
>ought to be using an event driven model (when what you're doing isn't
>nearly as linear, which does happen).
Certainly anything whose "one obvious way to do it" is a state machine
should be implemented as a state machine. But the specific examples I've
been talking about are things whose "obvious way to do it" is a
thread. And even when writing a state machine, it's quite likely that an
"obvious way to do it" is to write a Thread that acts as the dispatch loop!
> A facility like yours will surely lower the barrier to Twisted
> programming because as you said most programmers are far better
> linear/iterative thinkers. The real problem is, of course, that Python
> sucks at this concurrency which is why Twisted feels like the tail
> wagging the dog. I think that things could be made a LOT nicer with
> macros, but I don't see a version of Python with macros happening anytime soon.
Nope. On the whole, though, I think the API I've proposed to this point is
pretty minimal overhead: yield+resume is a small price to pay for
co-operative multitasking with ubiquitous "threads".
More information about the PEAK
mailing list