Multiprocessing code to calculate pi never finishes
Question:
I want to calculate pi. The procedure is simple:
- Make a 1×1 square and draw a circle in the square. Then divide by 4.
- Take two random values (x, y).
- If x2 + y2 ≤ 1 than the point is in the circle.
- Repeat the above N times.
- Count the inner points (I’ll call it K) and divide by all number of executions and multiply by four. (4 * K / N == Pi)
The more iterations, the more accurate the calculation.
For doing fast, I use multiprocessing library. But the multiprocessing code never finishes. What’s the problem?
import timeit
start = timeit.default_timer()
import random
from multiprocessing import Pool
N = 1000000
process_num = 4
def make_pi(end):
count_inbound = 0
for x in range(end):
the_x = random.random()
the_y = random.random()
if((the_x**2 + the_y**2) <= 1):
count_inbound += 1
return count_inbound
# Multiprocessing.
p = Pool(processes = process_num)
count_in = p.map(make_pi, [N/process_num for x in range(process_num)])
print(4*sum(count_in)/N)
# Normal.
##print(4*make_pi(N)/N)
stop = timeit.default_timer()
print(stop - start)
Answers:
I have test the same code on my mac.
It works just fine.
0.25 for multi process and 0.45 for single process.
Just change
[N/process_num for x in range(process_num)]
to
[int(N/process_num for x in range(process_num)]
Self answer.
the problem is process need to be closed.
so i add just one line.
if __name__ == "__main__":
than my code do work!
import timeit
start = timeit.default_timer()
import random
from multiprocessing import Pool
N = 1000000
process_num = 4
def make_pi(end):
count_inbound = 0
for x in range(end):
the_x = random.random()
the_y = random.random()
if((the_x**2 + the_y**2) <= 1):
count_inbound += 1
return count_inbound
if __name__ == "__main__":
#multiprocessing code
p = Pool(processes = process_num)
count_in = p.map(make_pi, [int(N/process_num) for x in range(process_num)])
print(4*sum(count_in)/N)
#normal code
#print(4*make_pi(N)/N)
stop = timeit.default_timer()
print(stop - start)
import time
import random
from multiprocessing import Pool
start = time.perf_counter()
N = 100000000
process_num = 96
def calc_pi(end):
count_inbound = 0
for x in range(end):
the_x = random.random()
the_y = random.random()
if((the_x**2 + the_y**2) <= 1):
count_inbound += 1
return count_inbound
if __name__ == "__main__":
multi_processing = 1
#multiprocessing code
if multi_processing == 1:
p = Pool()
#add with statement so that pool will close automatically.
with p:
count_in = p.map(calc_pi, [int(N/process_num) for x in range(process_num)])
print(4*sum(count_in)/sum([int(N/process_num) for x in range(process_num)]))
#You want to do a division by sum([int(N/process_num) for x in range(process_num)]) to preserve accuracy
else:
#normal code
print(4*calc_pi(N)/N)
finish = time.perf_counter()
print (f'Finished in {finish - start} seconds')
I want to calculate pi. The procedure is simple:
- Make a 1×1 square and draw a circle in the square. Then divide by 4.
- Take two random values (x, y).
- If x2 + y2 ≤ 1 than the point is in the circle.
- Repeat the above N times.
- Count the inner points (I’ll call it K) and divide by all number of executions and multiply by four. (4 * K / N == Pi)
The more iterations, the more accurate the calculation.
For doing fast, I use multiprocessing library. But the multiprocessing code never finishes. What’s the problem?
import timeit
start = timeit.default_timer()
import random
from multiprocessing import Pool
N = 1000000
process_num = 4
def make_pi(end):
count_inbound = 0
for x in range(end):
the_x = random.random()
the_y = random.random()
if((the_x**2 + the_y**2) <= 1):
count_inbound += 1
return count_inbound
# Multiprocessing.
p = Pool(processes = process_num)
count_in = p.map(make_pi, [N/process_num for x in range(process_num)])
print(4*sum(count_in)/N)
# Normal.
##print(4*make_pi(N)/N)
stop = timeit.default_timer()
print(stop - start)
I have test the same code on my mac.
It works just fine.
0.25 for multi process and 0.45 for single process.
Just change
[N/process_num for x in range(process_num)]
to
[int(N/process_num for x in range(process_num)]
Self answer.
the problem is process need to be closed.
so i add just one line.
if __name__ == "__main__":
than my code do work!
import timeit
start = timeit.default_timer()
import random
from multiprocessing import Pool
N = 1000000
process_num = 4
def make_pi(end):
count_inbound = 0
for x in range(end):
the_x = random.random()
the_y = random.random()
if((the_x**2 + the_y**2) <= 1):
count_inbound += 1
return count_inbound
if __name__ == "__main__":
#multiprocessing code
p = Pool(processes = process_num)
count_in = p.map(make_pi, [int(N/process_num) for x in range(process_num)])
print(4*sum(count_in)/N)
#normal code
#print(4*make_pi(N)/N)
stop = timeit.default_timer()
print(stop - start)
import time
import random
from multiprocessing import Pool
start = time.perf_counter()
N = 100000000
process_num = 96
def calc_pi(end):
count_inbound = 0
for x in range(end):
the_x = random.random()
the_y = random.random()
if((the_x**2 + the_y**2) <= 1):
count_inbound += 1
return count_inbound
if __name__ == "__main__":
multi_processing = 1
#multiprocessing code
if multi_processing == 1:
p = Pool()
#add with statement so that pool will close automatically.
with p:
count_in = p.map(calc_pi, [int(N/process_num) for x in range(process_num)])
print(4*sum(count_in)/sum([int(N/process_num) for x in range(process_num)]))
#You want to do a division by sum([int(N/process_num) for x in range(process_num)]) to preserve accuracy
else:
#normal code
print(4*calc_pi(N)/N)
finish = time.perf_counter()
print (f'Finished in {finish - start} seconds')