20ms以上の精度を求めるなら「time.perf_counter()」,それ以下で良いなら「time.process_time()」

「「time.process_time」は精度が悪いから使うべきではない」という記事をみて気になったので.

import time

num = 1000
mst = 0
for _ in range(num):
    t0 = time.perf_counter()
    while True:
        t1 = time.perf_counter()
        if t1 != t0:
            break
    mst = mst + (t1 - t0)

print(f'Resolution of the time.perf_counter: {mst/num:.9f} [sec]')
print(time.get_clock_info('perf_counter'))


#バージョン 3.3 で撤廃: この関数の挙動はプラットフォームに依存します: 
#必要に応じて挙動が明確に定義されている perf_counter() または process_time() を使用してください。
#16.3. time — 時刻データへのアクセスと変換-Python3.6.1ドキュメント より
mst = 0
for _ in range(num):
    t0 = time.clock()
    while True:
        t1 = time.clock()
        if t1 != t0:
            break
    mst = mst + (t1 - t0)

print(f'Time of the time.clock: {mst/num:.9f} [sec]')
print(time.get_clock_info('clock'))


mst = 0
for _ in range(num):
    t0 = time.process_time()
    while True:
        t1 = time.process_time()
        if t1 != t0:
            break
    mst = mst + (t1 - t0)

print(f'Time of the time.process_time: {mst/num:.7f} [sec]')
print(time.get_clock_info('process_time'))


mst = 0
for _ in range(num):
    t0 = time.monotonic()
    while True:
        t1 = time.monotonic()
        if t1 != t0:
            break
    mst = mst + (t1 - t0)

print(f'Time of the time.monotonic: {mst/num:.5f} [sec]')
print(time.get_clock_info('monotonic'))


mst = 0
for _ in range(num):
    t0 = time.time()
    while True:
        t1 = time.time()
        if t1 != t0:
            break
    mst = mst + (t1 - t0)

print(f'Time of the time.time: {mst/num:.5f} [sec]')
print(time.get_clock_info('time'))

Time of the time.perf_counter: 0.000000349 [sec]
namespace(adjustable=False, implementation=’QueryPerformanceCounter()’, monotonic=True, resolution=3.4800051086474995e-07)
Time of the time.clock: 0.000000355 [sec]
namespace(adjustable=False, implementation=’QueryPerformanceCounter()’, monotonic=True, resolution=3.4800051086474995e-07)
Time of the time.process_time: 0.0156250 [sec]
namespace(adjustable=False, implementation=’GetProcessTimes()’, monotonic=True, resolution=1e-07)
Time of the time.monotonic: 0.01562 [sec]
namespace(adjustable=False, implementation=’GetTickCount64()’, monotonic=True, resolution=0.015625)
Time of the time.time: 0.00100 [sec]
namespace(adjustable=True, implementation=’GetSystemTimeAsFileTime()’, monotonic=False, resolution=0.015625)

「time.perf_counter()」は非常に高精度で,分解能と同程度の精度が期待できる.

この環境では,「time.clock()」はQueryPerformanceCounter()が使われているので高精度だけど,環境依存でどの様な結果が返ってくるか分からない以上,ドキュメントに書かれている様に使わない方が良い.

「time.process_time()」は分解能は100 [ns]だが,精度は約15.6 [ms]しかない.昔,「GetProcessTimes()」を使った時は,分解能は100 [ns]程度だけど,精度はシステムタイマに依存するので,約15 [ms]程度だった覚えがある.今も変わっていない様だ.

time.monotonicは分解能と同程度の精度が期待される.PC起動から(約50日以内)の経過時間計測等,マクロな経過時間計測に良さそう.

time.timeはmonotonic=False(負値があり得る)なので,経過時間計測に用いるべきではないし,結果も一番尤もらしくない.マクロな日時計測で用いるべき.

追記:
上記は

計測環境:
Windows 10 Home(x64)
Intel Core i3 530

の話.参考までに,Linuxの場合.

計測環境:
Ubuntu 16.04.2 LTS(x86)
Celeron SU2300

Resolution of the time.perf_counter: 0.0000019219 [sec]
namespace(adjustable=False, implementation=’clock_gettime(CLOCK_MONOTONIC)’, monotonic=True, resolution=1e-09)
Resolution of the time.clock: 0.0000014790 [sec]
namespace(adjustable=False, implementation=’clock()’, monotonic=True, resolution=1e-06)
Resolution of the time.process_time: 0.0000014588 [sec]
namespace(adjustable=False, implementation=’clock_gettime(CLOCK_PROCESS_CPUTIME_ID)’, monotonic=True, resolution=1e-09)
Resolution of the time.monotonic: 0.0000018411 [sec]
namespace(adjustable=False, implementation=’clock_gettime(CLOCK_MONOTONIC)’, monotonic=True, resolution=1e-09)
Resolution of the time.time: 0.0000018256 [sec]
namespace(adjustable=True, implementation=’clock_gettime(CLOCK_REALTIME)’, monotonic=False, resolution=1e-09)

やはり,Windowsに比べてLinuxは分解能が高い.各関数については,Windowsの場合と同じ事が云える.time.timeは実時刻を計測したい場合に用いるべきで,処理時間(経過時間)の計測に用いるべきではない.処理の実時間(経過実時間)を得たいなら「CLOCK_MONOTONIC(time.perf_counter)」だし,計算コストとか処理にかかる時間(CPU時間)を知りたい場合は「CLOCK_PROCESS_CPUTIME_ID(time.process_time)」が望ましいだろう.

 
 

それに,timeitモジュールのデフォルトタイマーが「time.perf_counter()」である事を考えても,「time.perf_counter()」がリーズナブルチョイスになるだろう.

カテゴリー: 未分類 パーマリンク

20ms以上の精度を求めるなら「time.perf_counter()」,それ以下で良いなら「time.process_time()」 への2件のフィードバック

  1. ピンバック: disで手軽にPython バイトコードの逆アセンブル | 粉末@それは風のように (日記)

  2. ピンバック: Python(Numpy)で近似エントロピー(ApEn;Approximate Entropy ) | 粉末@それは風のように (日記)

コメントは受け付けていません。