コンピューターでも時間に遅れるんです。(思いやりの気持ち)

はじめに

コンピューターで「一定の時間の間処理を停止」する場合、pythonであれば

import time
time.sleep(0.01)

というようにします。当たり前だと思いますがこのプログラムは0.01秒待ちますが、実際には0.01秒ではありません。

何を言っているんだこいつは?

実証

以下のように0.01を10000回サンプリングして確かめてみます。

import time
now=0
result=[]
for i in range(10000):
    now=time.time()
    time.sleep(0.0001)
    result.append(time.time()-now)
print(sum(result)/len(result))
OUTPUT > 0.010746127510070801

0.010746127510070801となりましたね

いやこれ純粋にpythonが遅いからと思いましたか?ではヒストグラムで見てみましょう。

アイドル時の実際待ち時間

0.01待つ命令を実行しましたがこのように分布していることがわかります。

次にCPUに負荷ある場合にグラフを見てみましょう

高負荷時

高負荷のほうがまばらに散らばっていることがわかりますね。

ここでtime.sleep()の代わりに以下の関数を使ってみます。

この関数はsleepと違い待っている間CPUの1スレッドの使用率が100%になります。

def mysleep(s):
    now=time.time()
    while(time.time()-now<s):
        pass

結果が以下のグラフになります。

myseleep低負荷
mysleep高負荷

time.sleep()よりmysleepのほうが分布が一箇所に集まっています。

これはなぜでしょうか?

そもそもtime.sleep()とは?

この関数は主に一定時間待つために用いられるものです。しかしそれだけでは説明文は足りません。

time.sleep()とは、OSに指定した時間の間CPUの利用権限を返却(破棄)する意味があります。

そのため、sleepが実行されるとOSはsleepを実行したプログラムの実行を中断し、他のプログラムにCPUを利用させます。

この間はプログラムはCPU上にないので何もできません。(時間の確認も含めて)

ある程度時間が経過し、CPUが空くと、OSはsleepによって停止中のプログラムを復帰させます。

そのため、sleepの精度とはCPUの利用率やOSの精度に依存します。(なのでリアルタイムOSなどがあります。)

ちなみにですが、time.sleep(0)は何もしないわけではなく、一旦CPUの利用権を破棄するものになります。

一方mysleepは時間が経過するまで無限ループを行うものです。CPUを返却するどころか自分勝手に使いまくるものです。

そのためプログラム側がOSの気まぐれに左右されないため、精度良く時間を待つことができます。

まとめるとsleepとは、自分はしばらくやることがないから、他のプログラムに処理権を譲るという思いやりのある関数であることがわかります。