質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

722閲覧

Python 一時変数を挟むことでどれほど計算時間に影響するか

_Victorique__

総合スコア1392

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/10/09 07:53

python

1def crop_01(img): 2 cropped = img[0:100, 0:100] 3 return np.count_nonzero(cropped) 4 5def crop_02(img): 6 return np.count_nonzero(img[0:100, 0:100])

例えば画像を切り出してnp.count_nonzero()関数に突っ込むものがあったとします。
01の方が一時変数を利用していますが、02の方はダイレクトに引数に突っ込んでいます。
10000000回繰り返して01と02で速度に差は出るのでしょうか?
当方で速度差を計測しましたが実行順番によって偏りが出てしまい、正確な計測ができませんでした。
何か計測方法等のアドバイスや理論的な面からの議論があれば教えて欲しいです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

バイトコードディスアセンブラで見てみます。

python

1>>> def crop_01(img): 2... cropped = img[0:100, 0:100] 3... return np.count_nonzero(cropped) 4... 5>>> def crop_02(img): 6... return np.count_nonzero(img[0:100, 0:100]) 7... 8>>> import dis 9>>> dis.dis(crop_01) 10 2 0 LOAD_FAST 0 (img) 11 3 LOAD_CONST 1 (0) 12 6 LOAD_CONST 2 (100) 13 9 BUILD_SLICE 2 14 12 LOAD_CONST 1 (0) 15 15 LOAD_CONST 2 (100) 16 18 BUILD_SLICE 2 17 21 BUILD_TUPLE 2 18 24 BINARY_SUBSCR 19 25 STORE_FAST 1 (cropped) 20 21 3 28 LOAD_GLOBAL 0 (np) 22 31 LOAD_ATTR 1 (count_nonzero) 23 34 LOAD_FAST 1 (cropped) 24 37 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 25 40 RETURN_VALUE 26>>> dis.dis(crop_02) 27 2 0 LOAD_GLOBAL 0 (np) 28 3 LOAD_ATTR 1 (count_nonzero) 29 6 LOAD_FAST 0 (img) 30 9 LOAD_CONST 1 (0) 31 12 LOAD_CONST 2 (100) 32 15 BUILD_SLICE 2 33 18 LOAD_CONST 1 (0) 34 21 LOAD_CONST 2 (100) 35 24 BUILD_SLICE 2 36 27 BUILD_TUPLE 2 37 30 BINARY_SUBSCR 38 31 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 39 34 RETURN_VALUE

32.12. dis — Python バイトコードの逆アセンブラ — Python 3.6.5 ドキュメント

違うといえば違うし、crop_02の方が命令数が少ないので恐らく速いのだと思いますが……

単純な代入はたぶんpythonで一番速い処理なので、気にする必要はないです。スライスとnp.count_nonzeroが相対的に遅いので埋もれるということです。

追記

一応代入の有無による違いを確認しておきます。

passするだけの関数と、ローカル変数に代入して参照するだけの関数を動かします。

python

1import timeit 2 3import numpy as np 4from scipy import stats 5 6def f1(): 7 pass 8 9def f2(): 10 x = None 11 x 12 13a = [] 14b = [] 15for i in range(20): 16 a.append(timeit.timeit(f1)) 17 b.append(timeit.timeit(f2)) 18 19print(np.mean(a), np.mean(b)) 20print(stats.ttest_ind(a, b, equal_var = False)) 21 22""" 無駄に検定=> 230.08295731854450424 0.09186851899430622 24Ttest_indResult(statistic=-2.9737127732440825, pvalue=0.005209074456296565) 25"""

検定すれば確かに有意差はあるんですが、timeit.timeitはデフォルトで10^6回回して所要時間を測ります。

ということは、一回の代入&参照によって生じている差はわずか約9*10^-9[sec]。たった10ナノ秒弱の違いです。

やっぱり、気にする必要はないです。

投稿2018/10/09 08:13

編集2018/10/09 08:46
hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

_Victorique__

2018/10/09 08:17

disというモジュールの存在を知りませんでした。有り難うございます。 質問とは関係ありませんが、np.count_nonzeroより早い別の方法は存在するのでしょうか?
hayataka2049

2018/10/09 08:29

ないとは言い切れませんが、np.count_nonzeroは普通に速い部類の処理であるはずです
guest

0

IPythonで%timeitを使うと簡易的なベンチマークが取れます。

Python

1In [1]: import numpy as np 2In [2]: def crop_01(img): 3 ...: cropped = img[0:100, 0:100] 4 ...: return np.count_nonzero(cropped) 5 ...: 6 ...: def crop_02(img): 7 ...: return np.count_nonzero(img[0:100, 0:100]) 8 ...: 9 10In [3]: img = np.random.random(size=(400, 600)) 11 12In [4]: %timeit crop_01(img) 1341.1 µs ± 583 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each) 14 15In [5]: %timeit crop_02(img) 1641 µs ± 404 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

ほとんどパフォーマンスにほとんど差が出てないですね。NumPyのスライスcropped = img[0:100, 0:100]はメモリーへの参照を返すだけでコピーは発生しません。もちろん参照を保持する変数を確保する分だけオーバーヘッドがありますが、コピーに比べて参照を作るのは非常に高速なので今回のようなベンチマークでは差は計測できないでしょうね。

numpy.ndarray.view

投稿2018/10/09 08:25

tachikoma

総合スコア3601

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

_Victorique__

2018/10/09 08:29

> NumPyのスライスcropped = img[0:100, 0:100]はメモリーへの参照を返すだけでコピーは発生しません。 これはとっても重要なことですね。貴重な情報有難うございます。 まだまだ知らないことばかりで勉強不足ですね。
guest

0

計測に関して言うとウォームアップとして大量の計算を繰り返してから本計測に入ると実行順によるブレは出にくい可能性はあります。
が、おそらく差はないと思います。

投稿2018/10/09 08:14

mather

総合スコア6753

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問