[Stackless] Stackless and simulation

Christian Tismer tismer at tismer.com
Sat Apr 19 20:29:11 CEST 2003


sdfrost at UCSD.Edu wrote:
> Dear Stackless list,
> 
> If I may, I'd like to ask a few questions relating to the use of Stackless in 
> simulation. I'm trying to run some agent-based models, similar to that of 
> Boudewijn Rempt (modified for Stackless 2 by Aaron Watters). I'm playing 
> around with various implementations, including SimPy 
> (http://simpy.sourceforge.net), that uses generators to implement lightweight 
> threads a la David Mertz. I've also hacked up some simple models that don't 
> use generators (see the example below).

In the example you gave, I have a simple improvement to suggest:

"""
     def simulate(self,until):
         print str(Epidemic.now)+'\t'+str(Epidemic.numInfected[-1])
         while Epidemic.now <= until:
             try:
                 thisEvent=Epidemic.eventList.pop()
             except IndexError:
                 break
             Epidemic.now=thisEvent[0]
             thisEvent[1].makeContact()
"""

The only action that you want to do on an IndexError is breaking
the loop. In that context, you can save the overhead of creating
a new exception handler all the time. A single one does it,
under the assumption that cameContact() doesn't raise IndexError,
itself:

     def simulate(self,until):
         print str(Epidemic.now)+'\t'+str(Epidemic.numInfected[-1])
         try:
             while Epidemic.now <= until:
                 thisEvent=Epidemic.eventList.pop()
                 Epidemic.now=thisEvent[0]
                 thisEvent[1].makeContact()
         except IndexError:
             break

> Firstly, if I use tasklets to implement these models, will they be faster than 
> using generator or non-generator based implementations?

This is hard to tell. I think, in Stackless 3.0, tasklets and
generators should not differ very much in speed. Tasklets
might be marginally slower since they involve a little more
overhead, but since in most cases they can be run using
soft-switching, I belive that will not be noticeable.

I added the following test to my taskspeed.py:

# generator test
def gf(n):
     for i in xrange(0, n, 20):
         yield i; yield i; yield i; yield i; yield i
         yield i; yield i; yield i; yield i; yield i
         yield i; yield i; yield i; yield i; yield i
         yield i; yield i; yield i; yield i; yield i

def gentest(n):
     for i in gf(n):pass

Unfortunately, I cannot think of anything that involves less
Python code and runs reasonably faster. The iterator protocol
seems to be fastest here; unrolling calls to next() were
a bit slower than the short for loop.

Here my timings:

D:\slpdev\src\2.2\src\Stackless\test>..\..\pcbuild\python taskspeed.py
10000000 frame switches      took 3.73025 seconds, rate =    2680788/s
10000000 frame softswitches  took 2.30246 seconds, rate =    4343184/s
10000000 cfunction calls     took 2.07877 seconds, rate =    4810540/s
10000000 cframe softswitches took 0.49991 seconds, rate =   20003503/s
10000000 generator calls     took 3.72122 seconds, rate =    2687287/s
10000000 cframe switches     took 1.92401 seconds, rate =    5197489/s
10000000 cframe 100 words    took 3.96628 seconds, rate =    2521251/s
The penalty per stack word is about 1.061 percent of raw switching.
Stack size of initial stub   = 14
Stack size of frame tasklet  = 58
Stack size of cframe tasklet = 34

I have to say that this is not really fair for generators, since the
generator a) involves some Python opcodes, and b) always produces
a new result.
The tasklets were timed by single switches, and comparing them to
generators would probably require two switches, right?

So, raw switching speed might not be your criterion, but it depends
on how you implement your code, and how much code you can save
by using either generators or tasklets.

> Secondly, how would I modify my model to use tasklets rather than 
> generators/function calls?

Using tasklets or generators can save you something if you need
lots of local state of your individuals, for instance.
Tasklets have the benefit over generators, that you are not
restricted to a single frame, but you can switch them at any
recursion level. Using channels to communicate can give you
some speed-up, if its built-in blocking mechanism is of
advantage and saves you some code.
In the example you gave, I don't see much improvements by using
either. Maybe someone else has a better clue.

ciao - chris
-- 
Christian Tismer             :^)   <mailto:tismer at tismer.com>
Mission Impossible 5oftware  :     Have a break! Take a ride on Python's
Johannes-Niemeyer-Weg 9a     :    *Starship* http://starship.python.net/
14109 Berlin                 :     PGP key -> http://wwwkeys.pgp.net/
work +49 30 89 09 53 34  home +49 30 802 86 56  pager +49 173 24 18 776
PGP 0x57F3BF04       9064 F4E1 D754 C2FF 1619  305B C09C 5A3B 57F3 BF04
      whom do you want to sponsor today?   http://www.stackless.com/


_______________________________________________
Stackless mailing list
Stackless at www.tismer.com
http://www.tismer.com/mailman/listinfo/stackless




More information about the Stackless mailing list