すずろぐ

人生大逆転を目指す、鈴木俊吾の成長日記

Java 処理の実行時間を計測するプログラムを書いてみた

stopwatch

こんにちは、すずしんです。

Javaのプログラミングスキルのリハビリ企画第2弾としまして…。 今回は、ある処理実行時間計測するためのプログラムを書いてみました。 実行時間の計測を行う機能を持ったTimerクラスを作り、それと併せてサンプルプログラムで動作チェックをしてみます。

実行時間計測の基礎知識

Javaである処理の実行時間を計測するには、基本的にSystem.currentTimeMillisメソッドかSystem.nanoTimeメソッドを使います。 System.currentTimeMillisはミリ秒、System.nanoTimeはナノ秒の単位で時間を取得します。

計測したい処理の前でメソッドを呼び出してその瞬間の時間を変数で記録しておきます。 そして、処理が終わった時にも同様に呼び出し、前回との時間の差分をとります。 この差分が実行時間となります。

例えば、ミリ秒単位で、ある処理の実行時間を計測したい場合には…。 まず、long型の変数を2つ用意します。

long t0; // 処理開始前の時間を保持する
long time; // 実行時間を保持する

そして、計測したい処理の前でSystem.currentTimeMillisメソッドで時間を取得してt0に保持します。 目的の処理を行った後で再びSystem.currentTimeMillisメソッドを呼び出すのですが、ここでt0との差分を計算してtimeに保存します。 このtimeがミリ秒単位での実行時間を表しています。

t0 = System.currentTimeMillis();
(計測したい処理...)
time = System.currentTimeMillis() - t0;

TimerTestクラス

それでは、以上の事を踏まえて実行時間計測のサンプルプログラムとしてTimerTestクラスを作ってみました。 ソースコードは以下のようになります。 時間を計る処理の対象としては、スレッドを停止させるtaskメソッドを擬似的なタスクにしています。 変数を定義した後、短い処理、長い処理、複数の処理の実行時間を計測しています。

実行結果例

このプログラムを実行すると以下のような結果になります。 Thread.sleepメソッドは、指定した時間(ms)だけ処理をスリープするはずなのですが、実はスリープの時間には誤差が生じます。 そのため、実行する度に多少異なる結果になると思います。

task is processing...
time: 16 ms.
task is processing...
time: 1014 ms.
task is processing...
time: 1030 ms.

Timerクラス

TimerTestクラスのようにすれば実行時間を計測できるのですが…。 実行時間計測用のクラスを別に作って、それを利用したほうが便利ですよね。

というわけで、Timerクラスを作ってみました。 ソースコードは以下のようになります。 少々長いですが難しいことは特にしていません。

続いて、Timerクラスの仕様について書いていきます。

定数

Timerクラスに定義されている定数の一覧です。

MILLISECOND

計測時間の単位を表す定数です。 これはミリ秒を表します。 文字列で"ms"です。

SECOND

計測時間の単位を表す定数です。 これは秒を表します。 文字列で"s"です。

NANOSECOND

計測時間の単位を表す定数です。 これはナノ秒を表します。 文字列で"ns"です。

コンストラクタ

Timerクラスのコンストラクタ一覧です。

public Timer()

Timerクラスのインスタンスを生成します。 計測時間の単位はナノ秒単位になります。

public Timer(String timeUnit)

Timerクラスのインスタンスを生成します。 timeUnitで実行時間の単位を指定します。 timeUnitには、Timer.MILLISECOND、Timer.SECOND、Timer.NANOSECONDのいずれかを指定するようにしてください。

メソッド

Timerクラスのメソッド一覧です。

public String getTimeUnit()

現在設定されている時間単位を取得します。

public void setTimeUnit(String timeUnit)

時間単位をtimeUnitに設定します。 timeUnitには、Timer.MILLISECOND、Timer.SECOND、Timer.NANOSECONDのいずれかを指定するようにしてください。

public void start()

実行時間の計測を開始します。 計測したい処理の直前でこのメソッドを呼び出して下さい。

public void stop()

startメソッドを呼び出してからの経過時間を保存して計測を終了します。 計測したい処理の直後にこのメソッドを呼び出して下さい。

public double getTime()

計測した実行時間を現在設定されている時間単位で取得します。

TimerTest2クラス

それでは、Timerクラスを使って実行時間の計測をしてみます。 サンプルプログラムとしてTimerTest2というクラスを作ってみました。 ソースコードは以下のようになります。

TimerTest2では、実行時間の計測をするためにlong型の変数を使う代わりにTimerクラスを使うようにしています。 最初にTimerのインスタンスを生成します。 そして、実行時間を計りたい処理の前後でstartメソッドとstopメソッドを呼び出します。 実行時間の取得にはgetTimeメソッドを使います。 ちなみに、taskメソッドをこちらでも使いたいのでextendsでTimerTestクラスを継承させています。

実行結果例

このプログラムを実行した結果の例は以下のようになります。 TimerTestの時と同様に、それぞれの処理の実行時間が表示されているのが分かりますね。 内部的にナノ秒で計測したものをミリ秒で表示していますので精度が細かくなっています。

task is processing...
time: 10.719 ms.
task is processing...
time: 1012.583 ms.
task is processing...
time: 1027.784 ms.

まとめ

今回の記事では、ある処理の実行時間の計測を行うTimerクラスを作りました。 そして、サンプルプログラムでTimerの動作チェックをしてみました。

TimerTestとTimerTest2を比べてみると…。 TimerTest2の方がソースコードをぱっと見た時に、どんな処理をしているのかが直感的に分かりやすくなっていますよね。 それに、Timerクラスは今後実行時間を計測したい時に使い回しができます。

つまり、プログラムの可読性と再利用性が向上しているということです。 プログラミングをするうえで可読性と再利用性を良くすることは重要ですねっ! プログラマとしては常に意識しておきたいことです。 私は趣味でやっているレベルですけど…。

何かプログラムを作っていて、どこか処理が遅いと感じた時に、実際に処理の実行時間を計測してみる事は効果があります。 処理の実行時間を計測したい時には、ぜひこのTimerを使ってやって下さい。 1人でも多くの人が使って頂けると嬉しいです。