簡體   English   中英

如何測量經過的時間

[英]How to measure elapsed time

我有一個 10 和 20 個問題的游戲。 我需要計算用戶完成游戲時過去了多少時間。

Timer T=new Timer();
T.scheduleAtFixedRate(new TimerTask() {         
    @Override
    public void run() {
        runOnUiThread(new Runnable()
        {                
            public void run()
            {
                countdown.setText(""+count);
                count++;                
            }
        });
    }
}, 1000, 1000);

我用它來停止計數器:

T.cancel();

現在我需要兩件事:

  • 一種如何計算經過時間並將其存儲在變量中的方法
  • 我需要將最終值設為雙精度值,例如最終得分為:15.49 秒。

游戲開始時:

long tStart = System.currentTimeMillis();

游戲結束時:

long tEnd = System.currentTimeMillis();
long tDelta = tEnd - tStart;
double elapsedSeconds = tDelta / 1000.0;

根據 Android 文檔SystemClock.elapsedRealtime()是通用間隔計時的推薦基礎。 這是因為,根據文檔,elapsedRealtime() is guaranteed to be monotonic, [...], so is the recommend basis for general purpose interval timing.

SystemClock 文檔很好地概述了各種時間方法及其適用的用例。

  • SystemClock.elapsedRealtime()SystemClock.elapsedRealtimeNanos()是計算通用經過時間的最佳選擇。
  • SystemClock.uptimeMillis()System.nanoTime()是另一種可能性,但與推薦的方法不同,它們不包括深度睡眠時間。 如果這是您想要的行為,那么它們可以很好地使用。 否則堅持使用elapsedRealtime()
  • 遠離System.currentTimeMillis()因為這將返回“牆上”時鍾時間。 這不適合計算經過時間,因為掛鍾時間可能會向前或向后跳躍。 許多諸如 NTP 客戶端之類的東西會導致掛鍾時間跳躍和傾斜。 這將導致基於currentTimeMillis()經過時間計算並不總是准確的。

游戲開始時:

long startTime = SystemClock.elapsedRealtime();

游戲結束時:

long endTime = SystemClock.elapsedRealtime();
long elapsedMilliSeconds = endTime - startTime;
double elapsedSeconds = elapsedMilliSeconds / 1000.0;

此外, Timer() 是一個盡力而為的計時器,並不總是准確的。 因此,在游戲過程中會累積計時錯誤。 要更准確地顯示中間時間,請使用定期檢查System.currentTimeMillis()作為發送到setText(...)的時間的基礎。

此外,您可能想考慮使用TimerTask而不是使用Timer ,這個類是為您想要做的事情而設計的。 唯一的問題是它是倒數而不是倒數,但這可以通過簡單的減法來解決。

甚至更好!

long tStart = System.nanoTime();
long tEnd = System.nanoTime();
long tRes = tEnd - tStart; // time in nanoseconds

閱讀有關 nanoTime() 的文檔

有很多方法可以實現這一點,但測量經過時間的最重要的考慮因素是使用System.nanoTime()TimeUnit.NANOSECONDS作為時間單位。 我為什么要這樣做? 嗯,這是因為System.nanoTime()方法返回一個高分辨率的時間源,從某個參考點(即 Java 虛擬機的啟動)起以納秒為單位。

此方法只能用於測量經過的時間,與系統或掛鍾時間的任何其他概念無關。

出於同樣的原因,建議避免使用System.currentTimeMillis()方法來測量經過的時間。 此方法返回wall-clock時間,該時間可能會因多種因素而變化。 這將對您的測量產生負面影響。

請注意,雖然返回值的時間單位是毫秒,但該值的粒度取決於底層操作系統,可能會更大。 例如,許多操作系統以幾十毫秒為單位測量時間。

所以這里你有一個基於System.nanoTime()方法的解決方案,另一個使用Guava ,最后一個Apache Commons Lang

public class TimeBenchUtil
{
    public static void main(String[] args) throws InterruptedException
    {
        stopWatch();
        stopWatchGuava();
        stopWatchApacheCommons();
    }

    public static void stopWatch() throws InterruptedException
    {
        long endTime, timeElapsed, startTime = System.nanoTime();

        /* ... the code being measured starts ... */

        // sleep for 5 seconds
        TimeUnit.SECONDS.sleep(5);

        /* ... the code being measured ends ... */

        endTime = System.nanoTime();

        // get difference of two nanoTime values
        timeElapsed = endTime - startTime;

        System.out.println("Execution time in nanoseconds   : " + timeElapsed);
    }

    public static void stopWatchGuava() throws InterruptedException
    {
        // Creates and starts a new stopwatch
        Stopwatch stopwatch = Stopwatch.createStarted();

        /* ... the code being measured starts ... */

        // sleep for 5 seconds
        TimeUnit.SECONDS.sleep(5);
        /* ... the code being measured ends ... */

        stopwatch.stop(); // optional

        // get elapsed time, expressed in milliseconds
        long timeElapsed = stopwatch.elapsed(TimeUnit.NANOSECONDS);

        System.out.println("Execution time in nanoseconds   : " + timeElapsed);
    }

    public static void stopWatchApacheCommons() throws InterruptedException
    {
        StopWatch stopwatch = new StopWatch();
        stopwatch.start();

        /* ... the code being measured starts ... */

        // sleep for 5 seconds
        TimeUnit.SECONDS.sleep(5);

        /* ... the code being measured ends ... */

        stopwatch.stop();    // Optional

        long timeElapsed = stopwatch.getNanoTime();

        System.out.println("Execution time in nanoseconds   : " + timeElapsed);
    }
}

從 Java 8 開始,您可以嘗試以下操作:

import java.time.*;
import java.time.temporal.ChronoUnit;

Instant start_time = Instant.now();
// Your code
Instant stop_time = Instant.now();

System.out.println(Duration.between(start_time, stop_time).toMillis());

//or

System.out.println(ChronoUnit.MILLIS.between(start_time, stop_time));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM