jupyter notebookでmulti-threaded programming

single threadよりもmultiple-threadsの方が計算速度が速いということは容易に理解できる。しかし、実際にどれくらい高速なのかという疑問が湧いたので、早速速度比較をしてみた。

スポンサーリンク

ipyparallelを使う

conda install ipyparallelでipyparallelをインストールする。次に、jupyterホームからターミナルを開いて以下を入力する。

1
2
ipcluster nbextension enable
ipcluster start -n 16

クライアントをインポートして、dvに値を渡す。

from ipyparallel import Client
rc = Client()
rc.ids
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
dv = rc[:]

マンデルブロットを描く

マンデルブロ集合を描くコードを書く。マンデルブローとも言われている。個人的にはマンデルブロットと言っている。

@dv.parallel(block = True)
def mandel2(x, y, max_iters=80):
    c = complex(x, y)
    z = 0.0j
    for i in range(max_iters):
        z = z*z + c
        if z.real*z.real + z.imag*z.imag >= 4:
            return i
    return max_iters
def mandel1(x, y, max_iters=80):
    c = complex(x, y)
    z = 0.0j
    for i in range(max_iters):
        z = z*z + c
        if z.real*z.real + z.imag*z.imag >= 4:
            return i
    return max_iters
import numpy as np
x = np.arange(-2, 1, 0.01)
y = np.arange(-1, 1, 0.01)
X, Y = np.meshgrid(x, y)
%%time
im1 = np.reshape(list(map(mandel1, X.ravel(), Y.ravel())), (len(y), len(x)))
CPU times: user 341 ms, sys: 0 ns, total: 341 ms
Wall time: 340 ms
%%time
im2 = np.reshape(mandel2.map(X.ravel(), Y.ravel()),  (len(y), len(x)))
CPU times: user 75.2 ms, sys: 249 µs, total: 75.5 ms
Wall time: 125 ms
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
axes[0].grid(False)
axes[0].imshow(im1, cmap='jet')
axes[1].grid(False)
axes[1].imshow(im2, cmap='jet')
<matplotlib.image.AxesImage at 0x7fbae9b65080>

シングルスレッドバージョン

import matplotlib.pyplot as plt
import time

start_time = time.time()

def mandel1(x, y, max_iters=250):
    c = complex(x, y)
    z = 0.0j
    for i in range(max_iters):
        z = z*z + c
        if z.real*z.real + z.imag*z.imag >= 4:
            return i
    return max_iters

x = np.arange(-2, 1, 0.001)
y = np.arange(-1, 1, 0.001)
X, Y = np.meshgrid(x, y)

start = time.clock()
im1 = np.reshape(list(map(mandel1, X.ravel(), Y.ravel())), (len(y), len(x)))
plt.grid(False)
plt.imshow(im1, cmap='jet')
dt = time.time() - start_time
print("Mandelbrot created on CPU in %f s" % dt)
Mandelbrot created on CPU in 102.121429 s

multi-threaded version

import matplotlib.pyplot as plt
import time

start_time = time.time()

@dv.parallel(block = True)
def mandel2(x, y, max_iters=250):
    c = complex(x, y)
    z = 0.0j
    for i in range(max_iters):
        z = z*z + c
        if z.real*z.real + z.imag*z.imag >= 4:
            return i
    return max_iters

x = np.arange(-2, 1, 0.001)
y = np.arange(-1, 1, 0.001)
X, Y = np.meshgrid(x, y)

start = time.clock()
im2 = np.reshape(mandel2.map(X.ravel(), Y.ravel()), (len(y), len(x)))
plt.grid(False)
plt.imshow(im2, cmap='jet')
dt = time.time() - start_time
print("Mandelbrot created on CPU in %f s" % dt)
Mandelbrot created on CPU in 19.603561 s
102.121429/19.603561
5.209330539487189

multi-threaded versionはsingle thread versionの約5.2倍速い。

参考サイトhttps://people.duke.edu/~ccc14/sta-663-2017/11C_IPyParallel.html