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

Reply via email to