Mailing List Archive

Python microthreads
I have been interested in using Python to program simulated
swarms of interacting agents. For this purpose, I have implemented
what I call "microthreads" in Python, modifying Python's virtual
machine, and maintaining a frame stack for each thread. I have
successfully run 1500 threads simultaneously. Source code and some
example usages are available at
ftp://ftp.std.com/pub/wware/uthread.tgz
for anybody interested in this. This is a pre-pre-thinking-about-
alpha-some-day release, and probably buggy, but the examples run
as expected.
--
- - - - - - - - - - - - - - - - - - - - - - - -
Resistance is futile. Capacitance is efficacious.
Will Ware email: wware @ world.std.com
Python microthreads [ In reply to ]
Will Ware <wware-nospam@world.std.com> wrote:
[microthreads]

Okay, I am going to say not much at all, just that this sounds cool; I
think this kind of thing fills a gap with Python. We have game programmers
etc asking for the same type of things as well, I think.

So keep up the good work!

Regards,

Martijn
Python microthreads [ In reply to ]
Did you build it on top of Christian Tismers
Stackless Python, or is it a different kind of
modification to the VM?

--
Dirk
Where did you want to go again?

Will Ware schrieb in Nachricht ...
>I have been interested in using Python to program simulated
>swarms of interacting agents. For this purpose, I have implemented
>what I call "microthreads" in Python, modifying Python's virtual
>machine, and maintaining a frame stack for each thread.
[...]
Python microthreads [ In reply to ]
Dirk-Ulrich Heise (hei@adtranzsig.de) wrote:
: Did you build it on top of Christian Tismers
: Stackless Python, or is it a different kind of
: modification to the VM?

I haven't looked at Stackless Python, but it sounds like an unrelated
thing. As I recall, Stackless Python uses the C stack for everything
whereas normally Python has a piece of stack in each frame object.
It can do this because the compiler is smart enough to figure out
exactly how much stack will be needed for any function call. So
frameobjects have a field called f_valuestack which maintains the
arguments and local variables for that function.

What I did was to keep the frameobject exactly as it is in normal
Python, but invent a thread object with a stack for frameobjects,
and a couple more stacks for stack pointers and program counters.
Additionally, I modified the bytecode interpreter (eval_code2, in
ceval.c) so that it runs for a specified number of opcodes and
then stops, leaving the entire environment intact. This lets you
rotate thru several threads, executing each for a few opcodes, so
it looks like the threads are running simultaneously.
--
- - - - - - - - - - - - - - - - - - - - - - - -
Resistance is futile. Capacitance is efficacious.
Will Ware email: wware @ world.std.com
Python microthreads [ In reply to ]
Will Ware wrote:

> This lets you rotate thru several threads, executing each for a few
> opcodes, so it looks like the threads are running simultaneously.

And it works like a charm, thanks for your good work! :-)


//Klaus

--
···[ Magnetic Ink ]················································· ><> ···
···[ http://www.magnetic-ink.dk/recipes/ ]··································
Python microthreads [ In reply to ]
wware-nospam@world.std.com (Will Ware) writes:
> Dirk-Ulrich Heise (hei@adtranzsig.de) wrote:
> : Did you build it on top of Christian Tismers
> : Stackless Python, or is it a different kind of
> : modification to the VM?
> I haven't looked at Stackless Python, but it sounds like an unrelated
> thing. As I recall, Stackless Python uses the C stack for everything
> whereas normally Python has a piece of stack in each frame object.
> It can do this because the compiler is smart enough to figure out
> exactly how much stack will be needed for any function call. So
> frameobjects have a field called f_valuestack which maintains the
> arguments and local variables for that function.

No.. Stackless python does _not_ use C stack. Normal python does. AFAIK,
that's what the stackless stands for (purely frame objects and such).

> What I did was to keep the frameobject exactly as it is in normal
> Python, but invent a thread object with a stack for frameobjects,
> and a couple more stacks for stack pointers and program counters.
> Additionally, I modified the bytecode interpreter (eval_code2, in
> ceval.c) so that it runs for a specified number of opcodes and
> then stops, leaving the entire environment intact. This lets you
> rotate thru several threads, executing each for a few opcodes, so
> it looks like the threads are running simultaneously.

Sounds like something you could do with Stackless Python, or on top of,
fairly easily.

-Markus

--

"If you want to travel around the world and be invited to speak at
a lot of different places, just write a Unix operating system."
-- Linus Torvalds
Python microthreads [ In reply to ]
Will Ware schrieb in Nachricht ...
>Dirk-Ulrich Heise (hei@adtranzsig.de) wrote:
>: Did you build it on top of Christian Tismers
>: Stackless Python, or is it a different kind of
>: modification to the VM?
>
>I haven't looked at Stackless Python, but it sounds like an unrelated
>thing. As I recall, Stackless Python uses the C stack for everything

No, Christian wanted to eliminate the use of the C stack and works with
the frame objects as well. Maybe one of you two re-invented the wheel
of the other?

Anyway, i just wanted to know whether the two things are of independent
origins so i'll take a look at your modifications as well. Maybe you and
Christian should found a SIG, to me it seems like you have similar
goals. Count me as a fan.

--
i.A. EVM/HEI
Where did you want to go again?
Python microthreads [ In reply to ]
Will Ware schrieb in Nachricht ...
> I haven't looked at Stackless Python, but it sounds like
> an unrelated thing. As I recall, Stackless Python uses the
> C stack for everything...

Dirk-Ulrich Heise (hei@adtranzsig.de) wrote:
> No, Christian wanted to eliminate the use of the C stack
> and works with the frame objects as well. Maybe one of you
> two re-invented the wheel of the other?

It looks like wheel reinvention is definitely happening.
I've now looked a little bit at Christian's work, and it
looks like there is a lot in common. It probably makes
sense, at least in the long term, to implement microthreads
using Stackless Python. I'll need to study his work more
carefully before I'm ready to migrate.

> Anyway, i just wanted to know whether the two things are
> of independent origins...

Yes, they're independent. Christian has already been in
consultation with the gods of Python, so I think his work is
more in the mainstream spirit of the Python codebase. I
don't think CPython loses anything by being stackless, so
maybe stacklessness could be folded into the core release.
So implementing microthreads separately will become an
increasingly bad idea.

I don't know if Christian's version of eval_code2 can be
stepped a controlled number of opcodes. That would need to
be done for microthreads.
--
- - - - - - - - - - - - - - - - - - - - - - - -
Resistance is futile. Capacitance is efficacious.
Will Ware email: wware @ world.std.com
Python microthreads [ In reply to ]
[Will Ware, on his microthreads vs Christian Tismer's Stackless Python]
> ...
> Yes, they're independent. Christian has already been in
> consultation with the gods of Python, so I think his work is
> more in the mainstream spirit of the Python codebase.

So far Guido has neither embraced nor rejected it; still a work in progress,
of uncertain outcome. OTOH, your changes will never go in, because you went
out of your way to change ceval.c to use both brace and indentation styles
Guido hates <0.9 wink>.

> I don't think CPython loses anything by being stackless,

So far it has lost a little speed. That can probably be regained. Part of
Christian's agenda is seeing what it would take to implement 1st-class
continuations (in the Scheme sense) too, and his frame manipulations are
general enough to support that, and that costs something beyond mere
stacklessness.

> so maybe stacklessness could be folded into the core release.

Definitely the hoped-for outcome.

> So implementing microthreads separately will become an increasingly
> bad idea.

Yup. You would gain some nice properties too; e.g., you could lose the
hardcoded limit on frames per thread, and run many more threads because the
control structure for each could be much smaller thanks to not preallocating
space proportional to that max # of frames.

> I don't know if Christian's version of eval_code2 can be
> stepped a controlled number of opcodes.

There's no direct provision for that now.

> That would need to be done for microthreads.

Python already bytecode-slices "real threads" every N opcodes (set via
sys.setcheckinterval); you probably didn't need to invent another mechanism
for that, and it's more efficient to hijack the one that's there (checking
two counters per eval-loop trip is twice the pure overhead of checking one
...). So this one doesn't seem "deep".

Guido has let on that his primary objection to fake threads of any flavor is
that-- without an uncertain amount of additional widespread work --they'll
all block at I/O calls. If you think threads are good only for overlapping
I/O (with other I/O or with computation), that's a killer objection. I
personally see lots of uses for threads, but almost none for I/O <wink>.

doing-i/o-is-like-picking-someone-else's-nose-ly y'rs - tim
Python microthreads [ In reply to ]
Tim Peters (tim_one@email.msn.com) wrote:
> ...you went out of your way to change ceval.c to use both
> brace and indentation styles Guido hates <0.9 wink>.

For my own private tinkering, I usually use the default indentation
modes offered by "indent" and Emacs C-mode. This is a matter of
laziness, not principle. If it ever mattered, I'd happily defer to
another style.

> Python already bytecode-slices "real threads" every N
> opcodes (set via sys.setcheckinterval)

That looks like the right way to do it. Thanks for pointing
that out.

> ...fake threads of any flavor [would, without enormous effort] all
> block at I/O calls.

I envision using microthreads for dumb little agents in swarm-like
simulations (game examples: robot tanks, PacMan monsters) where
nothing like file I/O would ever come up. But yeah, it would be good
if there were eventually some documentation with discussion of
limitations.

For those who want to follow along at home: A PyThreadState has two
relevant fields. tstate->ticker counts down executed bytecodes
starting from tstate->interp->checkinterval, the same thing my
num_steps counter is doing, except that all the machinery already
exists in the core release. sys_setcheckinterval(), defined in
sysmodule.c, sets tstate->interp->checkinterval. "ticker" is a field
of a PyThreadState, "checkinterval" is a field of a
PyInterpreterState, both defined in Include/pystate.h.

The use of "ticker" as a bytecode-slicing mechanism is enabled by a
static flag called "things_to_do" in ceval.c. My "uthread.step"
function would need to set things_to_do, call eval_code2_loop, and
reset things_to_do to its prior state. I'm not yet sure how to handle
threads whose status is "still working". Maybe I need to add a
WHY_STILLWORKING enum value, and possibly flag the thread or frame in
some way to represent that status.
--
- - - - - - - - - - - - - - - - - - - - - - - -
Resistance is futile. Capacitance is efficacious.
Will Ware email: wware @ world.std.com
Python microthreads [ In reply to ]
I have slightly improved my microthreads package.
It now has a web page:

http://world.std.com/~wware/uthread.html

As before, the ftp download location is:

ftp://ftp.std.com/pub/wware/uthread.tgz

The new version defines new microthread-safe versions of
a queue and a random number generator. It also removes
the hard-coded limit on the size of frame stacks, which
are now linked lists.

I have made very modest progress toward a merge with
Stackless Python. My microthread effort will become
obsolete in not too many months as Christian makes more
progress, so I'm planning to invest more of my time in
tinkering with applications.
--
- - - - - - - - - - - - - - - - - - - - - - - -
Resistance is futile. Capacitance is efficacious.
Will Ware email: wware @ world.std.com