Author: Remi Meier <remi.me...@inf.ethz.ch> Branch: Changeset: r246:c5d6ed268f36 Date: 2014-04-08 18:54 +0200 http://bitbucket.org/pypy/benchmarks/changeset/c5d6ed268f36/
Log: add a benchmark which runs some worms on a grid (should benefit greatly from array-write barriers) diff --git a/multithread/threadworms/threadworms.py b/multithread/threadworms/threadworms.py new file mode 100644 --- /dev/null +++ b/multithread/threadworms/threadworms.py @@ -0,0 +1,193 @@ +# Threadworms (a Python/Pygame threading demonstration) +# By Al Sweigart a...@inventwithpython.com +# http://inventwithpython.com/blog +# Released under a "Simplified BSD" license + +# This is meant to be an educational example of multithreaded programming, +# so I get kind of verbose in the comments. + +from common.abstract_threading import atomic, Future +import time +import random, sys, threading + +# Setting up constants +CELLS_WIDE = 1000 # how many cells wide the grid is +CELLS_HIGH = 1000 # how many cells high the grid is +GRID = [] +NUM_STEPS = 0 +MAX_WORM_SIZE = 5 + + +UP = 'up' +DOWN = 'down' +LEFT = 'left' +RIGHT = 'right' + +HEAD = 0 +BUTT = -1 # negative indexes count from the end, so -1 will always be the last index + + +class Worm(threading.Thread): # "Thread" is a class in the "threading" module. + def __init__(self, name='Worm', maxsize=MAX_WORM_SIZE, color=None): + threading.Thread.__init__(self) + self.name = name + self.rnd = random.Random() + self.maxsize = maxsize + + if color is None: + self.color = (random.randint(60, 255), random.randint(60, 255), random.randint(60, 255)) + else: + self.color = color + + # GRID_LOCK.acquire() # block until this thread can acquire the lock + with atomic: + while True: + startx = random.randint(0, CELLS_WIDE - 1) + starty = random.randint(0, CELLS_HIGH - 1) + if GRID[startx][starty] is None: + break # we've found an unoccupied cell in the grid + + GRID[startx][starty] = self.color # modify the shared data structure + # GRID_LOCK.release() + + + self.body = [{'x': startx, 'y': starty}] + self.direction = random.choice((UP, DOWN, LEFT, RIGHT)) + + + def run(self): + for _ in xrange(NUM_STEPS): + if self.rnd.randint(0, 100) < 20: # 20% to change direction + self.direction = self.rnd.choice((UP, DOWN, LEFT, RIGHT)) + + with atomic: + # GRID_LOCK.acquire() # don't return (that is, block) until this thread can acquire the lock + + nextx, nexty = self.getNextPosition() + if nextx in (-1, CELLS_WIDE) or nexty in (-1, CELLS_HIGH) or GRID[nextx][nexty] is not None: + self.direction = self.getNewDirection() + if self.direction is None: + self.body.reverse() # Now the head is the butt and the butt is the head. Magic! + self.direction = self.getNewDirection() + + if self.direction is not None: + nextx, nexty = self.getNextPosition() + + if self.direction is not None: + GRID[nextx][nexty] = self.color # update the GRID state + self.body.insert(0, {'x': nextx, 'y': nexty}) # update this worm's own state + + if len(self.body) > self.maxsize: + GRID[self.body[BUTT]['x']][self.body[BUTT]['y']] = None # update the GRID state + del self.body[BUTT] # update this worm's own state (heh heh, worm butt) + else: + self.direction = self.rnd.choice((UP, DOWN, LEFT, RIGHT)) # can't move, so just do nothing for now but set a new random direction + + # GRID_LOCK.release() + + + def getNextPosition(self): + if self.direction == UP: + nextx = self.body[HEAD]['x'] + nexty = self.body[HEAD]['y'] - 1 + elif self.direction == DOWN: + nextx = self.body[HEAD]['x'] + nexty = self.body[HEAD]['y'] + 1 + elif self.direction == LEFT: + nextx = self.body[HEAD]['x'] - 1 + nexty = self.body[HEAD]['y'] + elif self.direction == RIGHT: + nextx = self.body[HEAD]['x'] + 1 + nexty = self.body[HEAD]['y'] + else: + assert False, 'Bad value for self.direction: %s' % self.direction + + return nextx, nexty + + + def getNewDirection(self): + x = self.body[HEAD]['x'] # syntactic sugar, makes the code below more readable + y = self.body[HEAD]['y'] + + newDirection = [] + if y - 1 not in (-1, CELLS_HIGH) and GRID[x][y - 1] is None: + newDirection.append(UP) + if y + 1 not in (-1, CELLS_HIGH) and GRID[x][y + 1] is None: + newDirection.append(DOWN) + if x - 1 not in (-1, CELLS_WIDE) and GRID[x - 1][y] is None: + newDirection.append(LEFT) + if x + 1 not in (-1, CELLS_WIDE) and GRID[x + 1][y] is None: + newDirection.append(RIGHT) + + if newDirection == []: + return None # None is returned when there are no possible ways for the worm to move. + + return self.rnd.choice(newDirection) + +def run(worms=2, steps=10000000): + global DISPLAYSURF, NUM_WORMS, NUM_STEPS, GRID + NUM_WORMS = int(worms) + NUM_STEPS = int(steps) / NUM_WORMS + + GRID = [] + for x in range(CELLS_WIDE): + GRID.append([None] * CELLS_HIGH) +#GRID_LOCK = threading.Lock() # pun was not intended + + # Draw some walls on the grid +# squares = """ +# ........................... +# ........................... +# ........................... +# .H..H..EEE..L....L.....OO.. +# .H..H..E....L....L....O..O. +# .HHHH..EE...L....L....O..O. +# .H..H..E....L....L....O..O. +# .H..H..EEE..LLL..LLL...OO.. +# ........................... +# .W.....W...OO...RRR..MM.MM. +# .W.....W..O..O..R.R..M.M.M. +# .W..W..W..O..O..RR...M.M.M. +# .W..W..W..O..O..R.R..M...M. +# ..WW.WW....OO...R.R..M...M. +# ........................... +# ........................... +# """ + #setGridSquares(squares) + + # Create the worm objects. + worms = [] # a list that contains all the worm objects + for i in range(NUM_WORMS): + worms.append(Worm()) + for w in worms: + w.start() # Start the worm code in its own thread. + + for t in worms: + t.join() + + + +def setGridSquares(squares, color=(192, 192, 192)): + squares = squares.split('\n') + if squares[0] == '': + del squares[0] + if squares[-1] == '': + del squares[-1] + + with atomic: + # GRID_LOCK.acquire() + for y in range(min(len(squares), CELLS_HIGH)): + for x in range(min(len(squares[y]), CELLS_WIDE)): + if squares[y][x] == ' ': + GRID[x][y] = None + elif squares[y][x] == '.': + pass + else: + GRID[x][y] = color + # GRID_LOCK.release() + + + + +if __name__ == '__main__': + run() _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit