# time で時間を計測する。

自分が書いたコードの中で、特定の箇所を測定したい時に使います。

# 1. 使い方 その1

開始時刻と終了時刻を計測して、あとは引き算すれば実行時間が計測できます。

import time


start_time = time.perf_counter()

x = 2
y = x*x

execution_time = time.perf_counter() - start_time
print(execution_time)
>>> print(execution_time)
0.0011645840000014118
>>> 

# time ではなく perf_counter を使う

そんなに厳密なことはしないのであまり気にしなくてもいいかなと思うのですが time.time よりも time.perf_counter を使った方が良さそうです。 実際、このあとご紹介させていただく標準ライブラリ timeit でも time.perf_counter が使われていました。

time.perf_counter 関数は UNIX 時間に依存しません。

time.perf_counter()
パフォーマンスカウンターの値 (小数点以下がミリ秒) を返します。 クロックは短期間の計測が行えるよう、可能な限り高い分解能をもちます。 これにはスリープ中の経過時間も含まれ、システム全体で一意です。

time.time 関数は UNIX 時間を返します。

time.time()
エポック からの秒数を浮動小数点数で返します。 ... これは一般に Unix 時間 と呼ばれています。

時刻は常に浮動小数点数で返されますが、すべてのシステムが 1 秒より高い精度で時刻を提供するとは限らないので注意してください。 この関数が返す値は通常減少していくことはありませんが、 この関数を 2 回呼び出し、その呼び出しの間にシステムクロックの時刻を巻き戻して設定した場合には、以前の呼び出しよりも低い値が返ることがあります。

# 2. 使い方 その2 - 関数で包む

ある決まった処理を行いたい場合は、関数で包むことが考えられます。

# 対話モード >>> にコピペで動きます。
import time


def measure(func):
    def wrapper(*args, **kargs):
        start_time = time.perf_counter()
        
        result = func(*args, **kargs)
        
        end_time = time.perf_counter()
        execution_time = end_time - start_time
        print(f'{func.__name__}: {execution_time}')
        return result
    return wrapper


# フィボナッチ数列
def fib(n):
    if n in (0, 1):
        return 1
    else: 
        return fib(n - 2) + fib(n - 1)


# こんな感じで呼び出します。
measure(fib)(30)
>>> # こんな感じで呼び出します。
... measure(fib)(30)
fib: 0.44943433099999996
1346269
>>> 

# 3. 使い方 - デコレータを使う

デコレータは関数の前後に処理を追加する時に使います。 これを応用して実行時間を計測します。 デコレータで包むと再帰呼び出しであったり、 色々な箇所で何度も呼び出したりされるときには使えなかったりするので、 自分はあまり使っていません。

# 対話モード >>> にコピペで動きます。
import time


def measure(func):
    def wrapper(*args, **kargs):
        start_time = time.perf_counter()
        
        result = func(*args, **kargs)
        
        end_time = time.perf_counter()
        execution_time = end_time - start_time
        print(f'{func.__name__}: {execution_time}')
        return result
    return wrapper


# 階乗
@measure
def factorize(n):
    b = 2
    fct = []
    while b * b <= n:
        while n % b == 0:
            n //= b
            fct.append(b)
        b = b + 1
    if n > 1:
        fct.append(n)
    return fct


factorize(6700417 * 2147483647)
>>> factorize(6700417 * 2147483647)
factorize: 1.618552507000004
[6700417, 2147483647]
>>> 

Pythonで処理の時間を計測する冴えた方法 - Qiita Pythonで実行時間を計測する方法 その1 - Qiita Python の デコレータとクロージャ

# 4. プロファイルとプロファイラ

遅い場所を特定したいときはプロファイラを使う どの関数がどれくらい処理時間を調べることを プロファイル を取ると言ったりします。 プロファイルを計測するツールを プロファイラ と言います。

Python には cProfile というプロファイルを取るツールが標準ライブラリにはいっています。 cProfile については、この次の次の記事でご紹介させていただきます。

昔、cProfile もプロファイラという言葉も知らなかったため、 簡易的なプロファイルを取るツールを自作しようとしてハマりました笑 再帰が、再帰の計測仕方がわからない... みたいな感じで笑 数日して、誰か作ってるやろ.. と思って検索したら cProfile が出てきました。