''' ========================================================================== Python for Parallelism in Introductory Computer Science Education SC '13 HPC Educators Program Steven Bogaerts, Wittenberg University Joshua Stough, Washington and Lee http://www.joshuastough.com/SC13 MIT License: see README_LICENSE.txt file: parallelMontePi.py author: stough, with Garrett Heath Koller Summary: Estimate pi with both a sequential and a parallel Monte Carlo model. This is the standard random darts estimation of pi. pi/4 is estimated by the proportion of random pairs (in [0,1)) within the unit circle. Uses the Pool/map paradigm. Each process in the pool iterates a number of times, returning how many of the iterations met the condition, and the results are totalled. $ python[3] parallelMontePi.py [1000000] See: http://docs.python.org/library/multiprocessing.html http://docs.python.org/py3k/library/multiprocessing.html ========================================================================== ''' from multiprocessing import Pool, Process, cpu_count import random, time, sys #Dependencies defined below main() def main(): """ The main method: -time montePi(N) for the input N (default 1000000) -time parallel version of montePi, where montePi(N/P) is computed independently for each of P processes. """ N = 1000000 if len(sys.argv) > 1: N = int(sys.argv[1]) #sequential timing start = time.time() result = montePi(N) pi_seq = 4.0*result/N elapsed = time.time() - start print("Sequential: With %d iterations and in %f seconds," % (N, elapsed)) print(" pi is approximated to be %f." % (pi_seq)) time.sleep(3) #parallel timing start = time.time() #split up the iterations among cpu_count processes. cpus = cpu_count() args = [N // cpus] * cpus for i in range(N % cpus): #Distribute extra work if work cannot be evenly distributed. args[i] += 1 #Instantiate the pool of processes pool = Pool(processes = cpus) #Compute subtotals. subtotals = pool.map(montePi, args) #The sum of the subtotals is the total number of random pairs in [0,1] #that were inside the unit disk (unit quarter-disk here). That #total divided by N is an estimate of pi/4. result = sum(subtotals) pi_par = 4.0*result/N elapsed = time.time() - start print("Parallel: With %d iterations and in %f seconds," % (N, elapsed)) print(" pi is approximated to be %f." % (pi_par)) def montePi(num): """ montePi(num) Given the number of iterations to perform, returns the number of iterations of this Monte Carlo estimation of Pi that were inside the area of the circle. 4*return/num is an estimate of pi. """ numInCircle = 0 for i in range(num): x = random.random() y = random.random() if x**2 + y**2 <= 1: numInCircle += 1 return numInCircle #Call the main method if run from the command line. if __name__ == '__main__': main()