/
multi.py
109 lines (95 loc) · 3.69 KB
/
multi.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import itertools
import multiprocessing
import sys
import datetime
# area of space to investigate
x1, x2, y1, y2 = -2.13, 0.77, -1.3, 1.3
# as for pure_python_2.py with z[i], q[i] dereferences removed
def calculate_z_serial_purepython(chunk):
q, maxiter, z = chunk
output = [0] * len(q)
for i in range(len(q)):
zi = z[i]
qi = q[i]
if i % 1000 == 0:
# print out some progress info since it is so slow...
print "%0.2f%% complete" % (1.0/len(q) * i * 100)
for iteration in range(maxiter):
zi = zi * zi + qi
if abs(zi) > 2.0:
output[i] = iteration
break
return output
def calc_pure_python(show_output):
# make a list of x and y values which will represent q
# xx and yy are the co-ordinates, for the default configuration they'll look like:
# if we have a 1000x1000 plot
# xx = [-2.13, -2.1242, -2.1184000000000003, ..., 0.7526000000000064, 0.7584000000000064, 0.7642000000000064]
# yy = [1.3, 1.2948, 1.2895999999999999, ..., -1.2844000000000058, -1.2896000000000059, -1.294800000000006]
x_step = (float(x2 - x1) / float(w)) * 2
y_step = (float(y1 - y2) / float(h)) * 2
x=[]
y=[]
ycoord = y2
while ycoord > y1:
y.append(ycoord)
ycoord += y_step
xcoord = x1
while xcoord < x2:
x.append(xcoord)
xcoord += x_step
q = []
for ycoord in y:
for xcoord in x:
q.append(complex(xcoord,ycoord))
z = [0+0j] * len(q)
print "Total elements:", len(z)
# split work list into continguous chunks, one per CPU
# build this into chunks which we'll apply to map_async
nbr_chunks = 4 #multiprocessing.cpu_count()
chunk_size = len(q) / nbr_chunks
# split our long work list into smaller chunks
# make sure we handle the edge case where nbr_chunks doesn't evenly fit into len(q)
import math
if len(q) % nbr_chunks != 0:
# make sure we get the last few items of data when we have
# an odd size to chunks (e.g. len(q) == 100 and nbr_chunks == 3
nbr_chunks += 1
chunks = [(q[x*chunk_size:(x+1)*chunk_size],maxiter,z[x*chunk_size:(x+1)*chunk_size]) for x in xrange(nbr_chunks)]
print chunk_size, len(chunks), len(chunks[0][0])
# create a Pool which will create Python processes
p = multiprocessing.Pool()
start_time = datetime.datetime.now()
# send out the work chunks to the Pool
# po is a multiprocessing.pool.MapResult
po = p.map_async(calculate_z_serial_purepython, chunks)
# we get a list of lists back, one per chunk, so we have to
# flatten them back together
# po.get() will block until results are ready and then
# return a list of lists of results
results = po.get() # [[ints...], [ints...], []]
output = []
for res in results:
output += res
end_time = datetime.datetime.now()
secs = end_time - start_time
print "Main took", secs
validation_sum = sum(output)
print "Total sum of elements (for validation):", validation_sum
if show_output:
import Image
import numpy as nm
output = nm.array(output)
output = (output + (256*output) + (256**2)*output) * 8
im = Image.new("RGB", (w/2, h/2))
# you can experiment with these x and y ranges
im.fromstring(output.tostring(), "raw", "RGBX", 0, -1)
im.show()
if __name__ == "__main__":
# get width, height and max iterations from cmd line
# 'python mandelbrot_pypy.py 100 300'
w = int(sys.argv[1]) # e.g. 100
h = int(sys.argv[1]) # e.g. 100
maxiter = int(sys.argv[2]) # e.g. 300
# we can show_output for Python, not for PyPy
calc_pure_python(True)