몬테카를로 방식은 반복된 무작위 추출을 이용하여 함수의 값을 확률적으로 계산하는 방식의 알고리즘을 말한다. 이 방식을 통해 아래와 같이 원주율을 추정할 수 있다.
0부터 1사이의 random한 x,y값을 n번 구했을 때에 이 x,y가 위 그림의 원 내부에 있는 경우가 m 번이었다고 가정해보자. n이 매우 큰 숫자가 된다면, 사각형 넓이 1중에서 1/4짜리 원이 차지 하는 비율은 m/n라고 할 수 있을 것이다.
위 과정을 통해 1/4짜리 원의 넓이를 구하고, 1/4 원의 넓이 = 1/4 * pie * r^2의 식(원의 넓이는 pie*r^2)을 통해 원주율 pie 를 추정할 수 있다.
위의 과정에서 시간이 가장 오래 걸리는 작업은 무수히 많은 random x, y 의 값을 생성하는 과정일 것이다. 이 과정을 multiprocessing 을 통해 가속화 해보자.
import os
import time
import random
def estimate_nbr_points_in_quarter_circle(nbr_estimates):
"""순수 파이썬을 사용해 단위 4분원 안에 들어간 점 개수를 세는 몬테 카를로 추정"""
print(f"""Executing estimate_nbr_points_in_quarter_circle
with {nbr_estimates:,} on pid {os.getpid()}\n""")
nbr_trials_in_quarter_unit_circle=0
for step in range(int(nbr_estimates)):
x=random.uniform(0,1)
y=random.uniform(0,1)
is_in_unit_circle=x*x+y*y<=1.0
nbr_trials_in_quarter_unit_circle+=is_in_unit_circle
return nbr_trials_in_quarter_unit_circle
from multiprocessing import Pool
nbr_samples_in_total=1e8
nbr_parallel_blocks=6
pool=Pool(processes=nbr_parallel_blocks)#pool 에 작업자 수 명시
nbr_samples_per_worker=nbr_samples_in_total/nbr_parallel_blocks
print("Making {:,} samples per {} worker".format(nbr_samples_per_worker,
nbr_parallel_blocks))
nbr_trials_per_process=[nbr_samples_per_worker]*nbr_parallel_blocks # 각 작업자가 할 작업의 수를 list로
t1=time.time()
nbr_in_quarter_unit_circles=pool.map(estimate_nbr_points_in_quarter_circle, # multi로 실행할 함수
nbr_trials_per_process) # 각 작업자들이 가져갈 process 갯수 표시
t2=time.time()
Executing estimate_nbr_points_in_quarter_circle
with 16,666,666.666666666 on pid 3235
Executing estimate_nbr_points_in_quarter_circle
with 16,666,666.666666666 on pid 3238
Executing estimate_nbr_points_in_quarter_circle
with 16,666,666.666666666 on pid 3236
Executing estimate_nbr_points_in_quarter_circle
with 16,666,666.666666666 on pid 3237
Executing estimate_nbr_points_in_quarter_circle
with 16,666,666.666666666 on pid 3239
Executing estimate_nbr_points_in_quarter_circle
with 16,666,666.666666666 on pid 3240
Making 16,666,666.666666666 samples per 6 worker
print(nbr_in_quarter_unit_circles)
pi_estimate=sum(nbr_in_quarter_unit_circles)*4/float(nbr_samples_in_total)
print("Estimated pi", pi_estimate)
print("Delta:", t2-t1)
[13088998, 13090624, 13088555, 13091653, 13093314, 13089257]
Estimated pi 3.14169604
Delta: 11.011059045791626