Iam trying to understand functional programming using scala. So the question is very basic. To start off, I have a trait which looks something like this
trait DebugLogger{
def time(stageName:String)(func : => Unit):Unit = {
val currentTime= System.currentTimeMillis()
println(s"Stage ${stageName} started at ${currentTime}")
func
println(s"Stage ${stageName} completed.. Took ${(System.currentTimeMillis() - currentTime)/1000.0} seconds")
}
}
Now I have a function which looks something like this
object GeneralRecap extends App with DebugLogger {
val aCondition: Boolean = true
val list1 = Seq(1,2,4,4)
val list2 = Seq('a','b','c','d')
time ("Time taken in for loop"){
val a1 = for (i <- list1;
j <- list2
) yield i * j
println(a1)
}
time("Time taken in flatmap") {
val c = list1 flatMap (number => list2.map(value => number * value))
println(c)
}
I was assuming the bytecode that both the functions would generate would be the same and was assuming both the functions would take the same time to process. However to my surprise this is how the output ended up with
Stage Time taken in for loop started at 1661398450618
List(97, 98, 99, 100, 194, 196, 198, 200, 388, 392, 396, 400, 388, 392, 396, 400)
Stage Time taken in for loop completed.. Took 0.011 seconds
Stage Time taken in flatmap started at 1661398450629
List(97, 98, 99, 100, 194, 196, 198, 200, 388, 392, 396, 400, 388, 392, 396, 400)
Stage Time taken in flatmap completed.. Took 0.001 seconds
So the flatmap map way takes 1/10th of the for loop time. Considering both the functions are n square, I would assume that it should have taken the same time. Any reason why the first one takes more time than the other
CodePudding user response:
There are all sorts of problems with that time
method. Firstly it is including the time for the first println
in the total, and secondly there may well be formatting code executed before the second time is captured.
This is a much better version:
def time(stageName: String)(func: => Unit): Unit = {
println(s"Starting ${stageName}")
val startTime = System.currentTimeMillis()
func
val endTime = System.currentTimeMillis()
val elapsed = (endTime - startTime) / 1000.0
println(s"Stage ${stageName} completed. Took $elapsed seconds")
}
More importantly you can't measure Scala performance on a single run. There is a lot of optimisation that happens during the run of a program that means that the first pass is usually significantly slower than the later ones.