Thread.sleep(0) のオーバーヘッドがヤバイ件
あるプログラムがどうも遅いので、調べてみると Thread.sleep(long) が怪しかった。もちろん、スリープしているならプロファイルで遅い結果が出てくるのも頷けるが、Thread.sleep に渡していた値は 0。
どうやら、Thread.sleep(0) のオーバーヘッドは予想以上に大きいらしい。
オーバーヘッドを調べる方法として、ループ内で実行して実行時間を測ることにした。まず何も処理しない版のループ。
public static void main(String[] args) { long s = System.currentTimeMillis(); for (int i = 0; i < Integer.MAX_VALUE; i++) { } long e = System.currentTimeMillis(); System.out.println(e - s + "ms"); } // 実行結果 3ms
3ms。
ここに、Thread.sleep(0) を入れて実行する。
public static void main(String[] args) { long s = System.currentTimeMillis(); for (int i = 0; i < Integer.MAX_VALUE; i++) { Thread.sleep(0); } long e = System.currentTimeMillis(); System.out.println(e - s + "ms"); } // 実行結果 580473ms
遅すぎる!!!!!!!!!
その時間なんと 580 秒、10分近い。あまりの遅さに愕然とした。
で、改善版。渡された時間が 0 なら return する if 文を入れた関数でくるんであげると、劇的に改善する。実質何もしない関数呼び出しの処理しか実行されず、オーバーヘッドはかなり少ない。
public static void main(String[] args) throws IOException, InterruptedException { long s = System.currentTimeMillis(); for (int i = 0; i < Integer.MAX_VALUE; i++) { mySleep(0); } long e = System.currentTimeMillis(); System.out.println(e - s + "ms"); } private static void mySleep(long time) throws InterruptedException { if (time == 0) return; Thread.sleep(time); } // 実行結果 4ms
まとめ
Thread.sleep(0) だからスリープなし版と同じ速度だぜ!!!というのは嘘。
0 を入れても遅い。