Showing posts with label break. Show all posts
Showing posts with label break. Show all posts

Friday, April 23, 2010

Break Performance

In the Breaks comments there were several questions about the performance of the Scala break command vs the Java break command. So I decided to take a look.

The code for the tests is available on GitHub at: Scala Benchmarks. Feel free to play around with it.

I personally don't think these tests say anything of particular import because they only test how fast the Java break is vs the Scala break without doing any work in the loop. So I don't expect these number would ever been seen in the real world. However that said if you have a tight loop with minimal processing then a Scala break may not be the correct construct to use.

Here is the Java test (labelled JavaSimpleBreak)
  1. int i = 0;
  2. while (i < 10) {
  3.   if(i==1) break;
  4.   i += 1;
  5. }

Here is the Scala test (labelled ScalaSimpleBreak)
  1. var i = 0;
  2. breakable {
  3.   while (i < 10) {
  4.     if(i==1) break;
  5.     i += 1;
  6.   }
  7. }

Out of curiosity I also added a test that created a new Exception each iteration (labelled ScalaException):
  1. var i = 0;
  2.   while (i < 10) {
  3.     if(i==1) throw new Exception();
  4.     i += 1;
  5.   }

And also a test that just throws the same ScalaBreak exception each time. This one is weird since Scala Simple Break also throws the same exception but is much much faster so I think there is something about popping the stack in the example compared to the ScalaSimpleBreak test.
  1. var i = 0;
  2. breakable {
  3. while (i < 10) {
  4. if(i==1) break;
  5. i += 1;
  6. }
  7. }

The results of the tests:

First, don't compare the break tests to the Exception tests. They are sufficiently different to not be worth comparing.
Second, remember that this is a micro benchmark and has very little relationship to reality.

90000000 iterations. Swapping every 90000000 tests
JavaSimpleBreak = 254 (0.0016279129387033098)
ScalaSimpleBreak = 2475 (0.015862537493270438)
ScalaBreakException = 18806 (0.12052964852462379)
ScalaException = 156028 (1.0)

90000000 iterations. Swapping every 500000 tests
JavaSimpleBreak = 772 (0.005138547761203965)
ScalaSimpleBreak = 2351 (0.015648608531853004)
ScalaBreakException = 19346 (0.12876987692778744)
ScalaException = 150237 (1.0)

90000000 iterations. Swapping every 500 tests
JavaSimpleBreak = 790 (0.005242446563543097)
ScalaSimpleBreak = 2247 (0.014911110668710557)
ScalaBreakException = 19213 (0.1274976276270298)
ScalaException = 150693 (1.0)

Tuesday, April 20, 2010

Breaks

Scala 2.8 added the break control flow option. It is not implemented as a special language feature. Rather it is simply implemented as an object/trait using standard Scala mechanisms. If you are interested in creating a control flow object similar to this look at the Defining Custom Control Structures post.

The Break functionality is works basically how you would expect:
  1. // Import the control flow methodsmethods
  2. scala> import util.control.Breaks._
  3. import util.control.Breaks._
  4. // pass a function to the breakable method
  5. scala> breakable {
  6.      | for (i <- 1 to 10 ) {
  7.      | if(i > 5) break  // call break when done
  8.      | println(i)
  9.      | }
  10.      | }
  11. 1
  12. 2
  13. 3
  14. 4
  15. 5

Pretty intuitive but beware, break only breaks out to the first enclosing breakable. Here is an example of the issue:
  1. scala> def loop(f : Int => Boolean) = breakable {
  2.      | for (i <- 1 to 300) if (f(i)) break else println(i)
  3.      | }
  4. loop: (f: (Int) => Boolean)Unit
  5. // This never ends because break is caught by breakable in the loop method
  6. scala> breakable {
  7.      | while(true) {
  8.      | loop{ i => break; true }
  9.      | }
  10.      | }

Fortunately the implementers provide an elegant way to handle these sorts of cases. The Breaks object extends the Breaks class. By instantiating other instances of Breaks it is possible to control which breaks capture
  1. scala> import scala.util.control._
  2. import scala.util.control._
  3. scala> 
  4. scala> def loop(f : Int => Boolean) = {
  5.      |   val Inner = new Breaks
  6.      |   Inner.breakable {
  7.      |     for (i <- 1 to 4) if (f(i)) Inner.break else println(i)
  8.      |   }
  9.      | }
  10. loop: (f: (Int) => Boolean)Unit
  11. scala> 
  12. scala> val Outer = new Breaks
  13. Outer: scala.util.control.Breaks = scala.util.control.Breaks@1ba4806
  14. scala> Outer.breakable {
  15.      |   while(true) {
  16.      |     loop{ i => if(i==4) Outer.break; false}
  17.      |   }
  18.      | }
  19. 1
  20. 2
  21. 3