Python で関数のパフォーマンスをテストするために time() を使用するのを直ちに中止してください。

time.monotonic() や time.perf_counter() の代わりに time.time() 関数を使用して Python でタスクのパフォーマンスを測定することに慣れていて、その理由を疑問に思っている場合は、この記事が最適です。

まずモジュールをインポートします。

improt time

簡単な例から始めましょう

話を簡単にするために、2 次元配列内の特定の値の出現数を数えることがタスクであるとします。ただし、これを行うだけでは満足できず、それにかかる時間も測定したいとします。コードの実装は次のとおりです。

def count_value(array, value):
   c = 0
   t_start = time.time()
   for i in array:
       for j in i:
           if j == value:
               c += 1
   t_end = time.time()

   return c, t_end-t_start

次に、いくつかの配列でこの関数を使用してみましょう。

a_1 = [[1,2],[3,3]]
a_2 = [[33]]
a_3 = [[1 for _ in range(10)] for _ in range(100)]
a_4 = [[i*j for j in range(1000)] for i in range(1000)]

print(count_value(a_1, 3))
print(count_value(a_2, 10))
print(count_value(a_3, 1))
print(count_value(a_4, 44))

出力:

(2, 0.0)
(0, 0.0)
(1000, 0.0)
(6, 0.03124070167541504)

実際の問題について説明する前に、デコレータを使用して関数のパフォーマンスを測定することをお勧めしますが、これはこの記事の範囲を超えているため、後で別の記事を書きます。それでは、上記の問題について話しましょう。4 つの配列のうち 3 つでは、検索のために測定された時間が 0 であることがわかります。これは、検索が即時であることを意味しますが、そうではありません。ここでの問題は、time.time() 関数がシステム クロックを使用していることです。質問:

  • このクロックのティック レートは十分小さくありません。タスクがクロックの 2 つの「ティック」の間に実行される場合、タスクの実際の長さを測定することはできません。これは、タスクの実際の長さを測定することができません。これは、クロックの分解能よりも短くなるからです。

  • システム クロックは、アップデート、クロック キャリブレーション、うるう秒などの外部要因によって変更される可能性があります。

これらの問題を解決するために、時間ライブラリには、monotonic() と perf_counter の 2 つの関数があります (または、ナノ秒の代替案も考慮する場合は、monotonic_ns() と perf_counter_ns() の 4 つの関数)。

これらの関数が両方の問題を解決することを知っておくことが重要です。monotonic() 関数は線形クロックに基づいており、外部から変更することはできませんが、perf_counter() 関数はより高いティック レートを持っています。

ティックレートの差を表示

time()、monotonic()、perf_counter の 3 つの関数すべての異なるティック レートを表示する関数を作成してみましょう。perf_counter_ns() を使用して経過時間を測定します。

def tick_rate(f):
   tick = 0
   t_start = time.perf_counter_ns()
   last_t = f()
   for i in range(10_000_000):
       t = f()
       if t != last_t:
           tick += 1
       last_t = t
   t_end = time.perf_counter_ns()

   return tick, (t_end-t_start)/(10**9) #divided by 10^9 to convert ns to s

print(tick_rate(time.time))
print(tick_rate(time.monotonic))
print(tick_rate(time.perf_counter))

出力:

(59, 0.9173757)
(50, 0.7825792)
(10000000, 1.615493)

perf_counter() 関数を使用して小さなタスクを測定する能力に大きな違いがあることがわかります、実際、perf_counter() で使用されるクロックの最大ティック レートは測定できませんが、それでも大きいです。機能はより長いタスクに使用できます。

perf_counter() を使用した同じ例 前と同じ例を使用しますが、time() の代わりに perf_counter() を使用します。

def count_value(array, value):
   c = 0
   t_start = time.perf_counter()
   for i in array:
       for j in i:
           if j == value:
               c += 1
   t_end = time.perf_counter()

   return c, t_end-t_start

a_1 = [[1,2],[3,3]]
a_2 = [[33]]
a_3 = [[1 for _ in range(10)] for _ in range(100)]
a_4 = [[i*j for j in range(1000)] for i in range(1000)]

print(count_value(a_1, 3))
print(count_value(a_2, 10))
print(count_value(a_3, 1))
print(count_value(a_4, 44))

出力:

(2, 4.7999997150327545e-06)
(0, 1.4000002011016477e-06)
(1000, 7.83999998930085e-05)
(6, 0.036078900000120484)

上で見たように、正しい関数を使用することで実際にかかった時間を測定できます。

次回の記事では、デコレーターについて、また関数のパフォーマンスを測定する際にデコレーターが最適である理由について説明します。この記事を最後まで読んだ方は、ぜひニュースレターの購読をご検討ください。無料ですし、モチベーションも維持できます。

原文:https://www.raaicode.com/using-time-monotonic-and-perf_counter-to-measure-time-in-python/

おすすめ

転載: blog.csdn.net/y1282037271/article/details/129200383