コンピュータ言語を遅く使ってしまう方法2
コンピュータを遅く使ってしまう方法はいろいろあるものです。
・部分配列を扱う際に不要なコピーを作らないこと。
処理系の言語・ライブラリが、部分配列の簡潔な記法をサポートしているときには、部分配列からなるコピーを作る代わりに、部分配列自体を関数の引数にするなどして処理することです。
Pythonのnumpyの例を示してみます。
次のように
B=A[3:6] はコピーを作らず、部分配列に対する別名になっているにすぎません。
別名なので、Bの要素を変更すると、元の配列に対しても変更になっています。
C=A[3:6]+0 はコピーを作ります。そのため、コピーを変更しても元の配列は変更されません。
この違いを知っていないと、「コピーを変更したつもりが元の配列まで変わってしまっていた。」という
初心者にありがちなエラーを引き起こすことになります。
>>> import numpy as np
>>> A=np.arange(0,10,1)
>>> A
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> A[3:6]
array([3, 4, 5])
>>> B=A[3:6] #これはコピーを作らない
>>> B[0]=-3
>>> A
array([ 0, 1, 2, -3, 4, 5, 6, 7, 8, 9])
>>> C=A[3:6]+0 # これはコピーを作る
>>> C
array([-3, 4, 5])
>>> C[0]=-30
>>> A
array([ 0, 1, 2, -3, 4, 5, 6, 7, 8, 9])
>>>
また、代入をその場での代入に置き換えれば速くなります。
*=, +=, -= などの利用を考えてみましょう。
# -*- coding: utf-8 -*-
import cv2
import numpy as np
e0 = cv2.getTickCount()
a = np.ones((1024, 1024))
for i in range(20):
a = a*2
print np.sum(a[:])
e1 = cv2.getTickCount()
a = np.ones((1024, 1024))
for i in range(20):
a *= 2
print np.sum(a[:])
e2 = cv2.getTickCount()
print (e1 - e0) / cv2.getTickFrequency(), "# a = a*2"
print (e2 - e1) / cv2.getTickFrequency(), "# a *= 2"
print (e2 - e1) / (e1 - e0)
実行結果
1.09951162778e+12
1.09951162778e+12
0.116400550283 # a = a*2
0.0270198481919 # a *= 2
0.23212818261
処理時間が23%にまで削減(4倍の高速化)になっています。
まとめ
・部分配列にコピーを作らない
・"*="で十分なときには"="を使わない。
Pythonの場合については「ハイパフォーマンスPython」
を読むといいでしょう。