## pqsort.py import threading, Queue, random # pqsort.py: threaded parallel quicksort # sorts an array in parallel with a fixed pool of worker threads # # adapted by Francis Hsu from Prof. Norm Matloff's # Shared-Memory Quicksort in Introduction to Parallel Programming # http://heather.cs.ucdavis.edu/~matloff/158/PLN/ParProc.pdf class pqsort: ''' threaded parallel quicksort ''' nsingletons = 0 # used to track termination nsingletonslock = None def __init__(self, a, numthreads = 5): ''' quicksorts array a in parallel with numthreads threads ''' jobs = Queue.Queue() # job queue pqsort.pqsorter.numthreads = 0 # thread creation count self.threads = [] # threads pqsort.nsingletons = 0 # count of positions that are sorted # done sorting when == to len(a) pqsort.nsingletonslock = threading.Lock() jobs.put((0,len(a))) for i in range(numthreads): # spawn threads t = pqsort.pqsorter(a, jobs) self.threads.append(t) t.start() for t in self.threads: # wait for threads to finish t.join() def report(self): for t in self.threads: t.report() class pqsorter(threading.Thread): ''' worker thread for parallel quicksort ''' numthreads = 0 # thread creation count def __init__(self, a, jobs): self.a = a # array being handled by this thread self.jobs = jobs # Queue of sorting jobs to do pqsort.pqsorter.numthreads += 1 # update count of created threads self.threadid = self.numthreads # unique id of this thread self.loop = 0 # work done by thread threading.Thread.__init__(self) def run(self): ''' thread loops taking jobs from queue until none are left ''' while pqsort.nsingletons < len(self.a): try: job = self.jobs.get(True,1) # get job # Queue handles the locks for us except: continue if job[0] >= job[1]: # partitioning an array of 1 pqsort.nsingletonslock.acquire() pqsort.nsingletons+=1 pqsort.nsingletonslock.release() continue self.loop +=1 m = self.separate(job) # partition self.jobs.put((job[0], m)) # create new jobs to handle the self.jobs.put((m+1, job[1])) # new left and right partitions def separate(self, (low, high)): ''' quicksort partitioning with first element as pivot ''' pivot = self.a[low] last = low for i in range(low+1,high): if self.a[i] < pivot: last += 1 self.a[last], self.a[i] = self.a[i], self.a[last] self.a[low], self.a[last] = self.a[last], self.a[low] return last def report(self): print "thread", self.threadid, "visited array", self.loop , "times" def main(): ''' pqsort timesharing analysis ''' for size in range(10): a = range(100*(size+1)) shufflesort(a) def shufflesort(a): #shuffle array for i in range(len(a)): r = random.randint(i, len(a)-1) (a[i], a[r]) = (a[r], a[i]) #sort array s = pqsort(a) print "For sorting an array of size", len(a) s.report() if __name__ == '__main__': main() ## Timesharing analysis ## ## % python pqsort.py ## For sorting an array of size 100 ## thread 1 visited array 88 times ## thread 2 visited array 12 times ## thread 3 visited array 0 times ## thread 4 visited array 0 times ## thread 5 visited array 0 times ## For sorting an array of size 200 ## thread 1 visited array 189 times ## thread 2 visited array 0 times ## thread 3 visited array 11 times ## thread 4 visited array 0 times ## thread 5 visited array 0 times ## For sorting an array of size 300 ## thread 1 visited array 226 times ## thread 2 visited array 74 times ## thread 3 visited array 0 times ## thread 4 visited array 0 times ## thread 5 visited array 0 times ## For sorting an array of size 400 ## thread 1 visited array 167 times ## thread 2 visited array 112 times ## thread 3 visited array 41 times ## thread 4 visited array 58 times ## thread 5 visited array 22 times ## For sorting an array of size 500 ## thread 1 visited array 249 times ## thread 2 visited array 125 times ## thread 3 visited array 100 times ## thread 4 visited array 17 times ## thread 5 visited array 9 times ## For sorting an array of size 600 ## thread 1 visited array 87 times ## thread 2 visited array 185 times ## thread 3 visited array 120 times ## thread 4 visited array 105 times ## thread 5 visited array 103 times ## For sorting an array of size 700 ## thread 1 visited array 295 times ## thread 2 visited array 278 times ## thread 3 visited array 54 times ## thread 4 visited array 32 times ## thread 5 visited array 41 times ## For sorting an array of size 800 ## thread 1 visited array 291 times ## thread 2 visited array 217 times ## thread 3 visited array 52 times ## thread 4 visited array 204 times ## thread 5 visited array 36 times ## For sorting an array of size 900 ## thread 1 visited array 377 times ## thread 2 visited array 225 times ## thread 3 visited array 113 times ## thread 4 visited array 128 times ## thread 5 visited array 57 times ## For sorting an array of size 1000 ## thread 1 visited array 299 times ## thread 2 visited array 233 times ## thread 3 visited array 65 times ## thread 4 visited array 249 times ## thread 5 visited array 154 times ## killthread.py import threading class TestThread(threading.Thread): def __init__(self, name='TestThread'): self._stopevent = threading.Event() self._sleepperiod = 1.0 threading.Thread.__init__(self) def run(self): print "%s starts" % (self.getName(),) count = 0 while not self._stopevent.isSet(): count +=1 print "loop %d" % (count,) self._stopevent.wait(self._sleepperiod) print "%s ends" % (self.getName(),) def join(self, timeout=None): self._stopevent.set() threading.Thread.join(self, timeout) if __name__ == "__main__": testthread = TestThread() testthread.start() import time time.sleep(10.0) testthread.join()