Scala测量程序运行时间

1. 简单使用

//定义测量函数
def timer[R](block: => R): R = {
    val t0 = System.nanoTime()//System.nanoTime为纳秒
    val result = block    // call-by-name
    val t1 = System.nanoTime()
    println("Elapsed time: " + (t1 - t0) + "ns")
    result
}
//使用测量函数:
timer{
你想要跑的程序
}
//例:
timer{List.range(1,1000, 1)}
注意!!

在 JVM 中的某些运行时优化技术,可能会去除调用block 代码块的语句,那么得到的运行时间就不是真正的运行时间了。于是为了避免这种情况,可以把代码块的返回值,赋予名为 result 的 Volatile 的字段。修改代码如下:

@volatile var result: Any = _
//定义测量函数
def timer[R](block: => R): R = {
    val t0 = System.nanoTime()//System.nanoTime为纳秒
    val result = block    // call-by-name
    val t1 = System.nanoTime()
    println("Elapsed time: " + (t1 - t0) + "ns")
    result
}

volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其他线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

2. 更通用的方法

//如下代码写入StopWatch.scala文件中


import java.util.concurrent.TimeUnit

import scala.collection.mutable.{ArrayBuffer, ListBuffer}

/**
  * 用于计算性能的秒表
  *
  */
@SerialVersionUID(1L)
class StopWatch(name: String) extends Serializable {
    private val stops = ListBuffer.empty[(Long, String)]

    /**
      * 开始秒表
      */
    def start(): StopWatch = {
        stops.append((System.currentTimeMillis(), "start"))
        this
    }

    /**
      * 一次计时打点
      *
      * @param description 对本次计时的描述
      */
    def click(description: String): StopWatch = {
        stops.append((System.currentTimeMillis(), description))
        this
    }

    /**
      * 停止表秒
      */
    def stop(): StopWatch = {
        stops.append((System.currentTimeMillis(), "stop"))
        this
    }

    /**
      * 重置秒表
      */
    def reset(): StopWatch = {
        stops.clear()
        this
    }

    /**
      * 输出耗时总结,会校验是否是有开始和结束的有效计时
      *
      * @return 返回总结结果,一次计时打点是一行
      */
    def summary(): String = {
        val stopsList = stops.toList
        require(stopsList.head._2 == "start" && stopsList.last._2 == "stop", "StopWatch must call start and stop method!")

        val summary = ArrayBuffer.empty[String]
        summary.append(System.lineSeparator())
        summary.append(s"Summary of StopWatch: $name")

        val startTime = stopsList.head._1
        val stopTime = stopsList.last._1
        summary.append(s"Total elapse time: ${StopWatch.formatElapseTime(stopTime - startTime)}")

        val restStops = stopsList.filter(click => click._2 != "start")
        restStops.zipWithIndex.foreach {
            case ((ts: Long, desc: String), index: Int) =>
                val startTs = if (index > 0) restStops(index - 1)._1 else stopsList.head._1
                summary.append(s"Click ${index + 1} [$desc]: elapse time is ${StopWatch.formatElapseTime(ts - startTs)}")
        }

        summary.toList.mkString(System.lineSeparator())
    }
}

/**
  * 伴随对象
  */
object StopWatch {
    /**
      * 定义 apply 函数
      *
      * @param name 秒表名称
      * @return 返回实例
      */
    def apply(name: String): StopWatch = new StopWatch(name)

    /**
      * 格式化耗时,转换成 x hour(s) y minute(s) z second(s)
      *
      * @param duration 耗时,单位毫秒
      * @return 返回格式化的耗时字符串
      */
    def formatElapseTime(duration: Long): String = {
        val resultBuffer = ArrayBuffer.empty[String]

        val hours = TimeUnit.MILLISECONDS.toHours(duration)
        resultBuffer.append(
            if (hours > 1) s"$hours hours "
            else if (hours > 0) s"$hours hour "
            else ""
        )

        var dur = duration - TimeUnit.HOURS.toMillis(hours)
        val minutes = TimeUnit.MILLISECONDS.toMinutes(dur)
        resultBuffer.append(
            if (minutes > 1) s"$minutes minutes "
            else if (minutes > 0) s"$minutes minute "
            else if (hours > 0) "0 minute "
            else ""
        )

        dur = dur - TimeUnit.MINUTES.toMillis(minutes)
        val seconds = TimeUnit.MILLISECONDS.toSeconds(dur)
        resultBuffer.append(
            if (seconds > 1) s"$seconds seconds"
            else if (seconds > 0) s"$seconds second"
            else "0 second"
        )

        resultBuffer.mkString("")
    }
}

//使用:
val stopWatch = new StopWatch("你的程序名").start()
...//跑一些代码
stopWatch.click("中途标识说明")
...//跑一些代码
println(s"耗时:\n${stopWatch.stop().summary()}")

参考:
http://biercoff.com/easily-measuring-code-execution-time-in-scala/
https://www.zybuluo.com/runzhliu/note/1121568

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值