Python ランダムチョイスに常時secretsを使ってもいいのか?

こんにちはRcatです。
今回はPythonでランダムな値を取得したり、リストからチョイスしたりするモジュールについて見ていきます。皆さんがよく知っているrandomと暗号関連のsecretsです。



はじめに

利用規約

情報や作品の活用時は事前に利用規約をご確認ください。

コメントについて

利用規約のガイドラインを確認の上コメントしてください


概要

まずランダムライブラリといえば、真っ先に思いつくのが"random"モジュールですよね。これは擬似乱数というものを使用してランダムの値を取得したり、リストからのチョイスを行ったりすることができるライブラリです。

これ以外にもランダムな値を取得するものとして"secrets"ライブラリがあります。
これは暗号学的に強い乱数を生成するためのモジュールです。例えば、Webサーバーで一時的なトークンを払い出したりするのに使います。

私はWebサーバーとかをよく使うので、これを知ってからはライブラリは常時secretsを使うようにしているんですが、それって本当にいいんだっけ?と思うようになりました。具体的には実行速度とかパフォーマンス的な話ですね。
ただ、常時使っていれば実は必要だったのに使ってなかったというのを防ぐことができます
というわけで常時採用すべきかそうでないのか実験してみることにしました。


計測

計測方法と判断基準

結局のところ気になるのはパフォーマンスなので、それを判断材料に今後どうするべきか判断していきます。

今回はコードの実行速度を測るモジュールを使います。
その名もtimeitこのライブラリは指定されたコードを100万回実行してかかった時間を返すライブラリです。実行回数は任意で設定可能です。

timeitの使い方

timeitライブラリはインポートした後、文字列でPythonコードを指定します。

>>> import timeit
>>> timeit.timeit("ここに計測したいコードを入力する")

上記の例では指定されたコードを単純に100万回繰り返してかかった時間を返します。

これを応用し、以下のように計測用のコードを組み立てます。

>>> import timeit
>>> import secrets
>>> import random
>>> L = [1,2,3,4,5]
>>> timeit.repeat("secrets.choice(L)", globals=globals(),repeat=5)
>>> timeit.repeat("random.choice(L)", globals=globals(),repeat=5)

コード解説は次の通りです。

今回比較するための2つのライブラリをインポートしています。
次に両方のライブラリでサポートされているリストの中からランダムに選択する機能を使って性能を比較します。

計測に使用するのはrepeatメソッドです。これを使うことで100万回繰り返すのをさらに何回やるかというのを指定できます。
今回はさらに5回やるので合計で500万回ですが、100万回を実行中のパソコンの負荷で若干変化があると考えられるので、平均を取るために使います。

次にglobals引数です。timeitライブラリですが、通常は文字列で指定されたコード以外は一切利用できません。
つまりインポートから書かないと本当はいけないんですが、globals引数を使うことでグローバル名前空間に入っている全てのモジュールや変数、関数が利用可能になります。
上記の理由から文字列と指定指定しなければならないコードは"secrets.choice(L)"のみとなります。インポートやリストの初期化なども500万回繰り返すなんて馬鹿らしいですからね…。

実行結果

というわけで実行結果も書いてある完全なるコードがこちらです。
secretsの方は大体0.8秒くらいですね。randomの方は0.3秒以内に終わっているので、3倍未満の時間差があることが分かります。

>>> import timeit
>>> import secrets
>>> import random
>>> L = [1,2,3,4,5]
>>> timeit.repeat("secrets.choice(L)", globals=globals(),repeat=5)
[0.8056212999999843, 0.8167384999999285, 0.826241399999958, 0.8098201999999901, 0.7978398999999854]
>>> timeit.repeat("random.choice(L)", globals=globals(),repeat=5)
[0.2889428000000862, 0.2916066000000228, 0.29753389999996216, 0.29312069999991763, 0.29643749999991087]

まとめ

今回はtimeitモジュールを使って乱数を使ったランダムチョイスができるrandom、secretsライブラリのスピードを計測しました。
暗号化の方を使うと3倍以上の時間がかかるという言い方もできますが、100万回実行しても1秒かからないという言い方もできます。
ですので、プログラムの中でどれくらい頻繁にランダムチョイスを呼び出すのかで考えた方が良さそうですね。
私の場合はそんなに頻繁に呼び出すことはないので、常時暗号対応の方を続けていくつもりです。
それではまたお会いしましょう。


いいなと思ったら応援しよう!

Rcat999
情報が役に立ったと思えば、僅かでも投げ銭していただけるとありがたいです。