Created
February 4, 2011 07:21
-
-
Save heuristicfencepost/810840 to your computer and use it in GitHub Desktop.
Implementation of various Scala tests to demonstrate integration with Java's fork/join framework
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.fencepost.forkjoin | |
import scala.collection.mutable.LinkedList | |
import jsr166y._ | |
import org.scalatest.Suite | |
class ForkJoinTest extends Suite { | |
val cache = new LinkedList[(()=>Int,Wrapper[Int])]() | |
class Wrapper[T](somefunc:()=>T) extends RecursiveTask[T] { | |
override def compute = somefunc.apply | |
// RecursiveTask.compute() is protected and there's no obvious way to | |
// elevate it's access level within a Scala class definition. The type | |
// system (very correctly) doesn't allow a random function access to | |
// protected methods of a class even when that method is invoked by | |
// a method within the class itself. Defining a new method with standard | |
// access resolves the issue. | |
def surrogate = compute | |
} | |
// Rationale for a caching implicit conversion can be found below. We use | |
// a list of tuples rather than a map since hashing buys us nothing here; | |
// there is always one (and exactly one) object with a given object identity. | |
implicit def fn2wrapper(fn:()=>Int):Wrapper[Int] = { | |
val cacheval = cache find (t => (t != null) && (t._1 eq fn)) | |
cacheval match { | |
case Some((_,cval)) => cval | |
case None => { | |
val newcval = new Wrapper[Int](fn) | |
cache.next = cache.next :+ (fn,newcval) | |
newcval | |
} | |
} | |
} | |
def testFibonacci() = { | |
def fib(n:Int):Int = { | |
if (n <= 1) | |
return n | |
// The approach used here only works if our implicit conversion always | |
// returns the same Wrapper instance for a given function. For a given | |
// RecursiveTask instance join() must be called on the same instance that | |
// originally called fork(). It follows that an implicit conversion such | |
// as: | |
// | |
// implicit def fn2wrapper(fn:()=>Int):Wrapper[Int] = { | |
// return new Wrapper(fn) | |
// } | |
// | |
// won't be adequate; fork() and join() will be called on two separate | |
// objects (since implicit conversion is performed on each method call) | |
// and join() will never return. | |
// | |
// Alternately we can force conversion when f1 and f2 are assigned values | |
// using something like the following; | |
// | |
// val f1:Wrapper[Int] = { ()=> fib(n - 1) } | |
// val f2:Wrapper[Int] = { ()=> fib(n - 2) } | |
// | |
// Clearly in this case f1.fork() and f1.join() will be called on the | |
// same instance of a RecursiveTask subclass. | |
val f1 = { ()=> fib(n - 1) } | |
f1 fork | |
val f2 = { ()=> fib(n - 2) } | |
(f2 surrogate) + (f1 join) | |
} | |
val pool = new ForkJoinPool() | |
assert ((pool invoke { ()=> fib(1) }) == 1) | |
assert ((pool invoke { ()=> fib(2) }) == 1) | |
assert ((pool invoke { ()=> fib(3) }) == 2) | |
assert ((pool invoke { ()=> fib(4) }) == 3) | |
assert ((pool invoke { ()=> fib(5) }) == 5) | |
assert ((pool invoke { ()=> fib(6) }) == 8) | |
assert ((pool invoke { ()=> fib(7) }) == 13) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.fencepost.forkjoin | |
import jsr166y._ | |
import org.scalatest.Suite | |
class ForkJoinTestFailOne extends Suite { | |
implicit def fn2wrapper(fn:()=>Int):RecursiveTask[Int] = { | |
return new RecursiveTask[Int] { override def compute = fn.apply } | |
} | |
def testFibonacci() = { | |
def fib(n:Int):Int = { | |
if (n <= 1) | |
return n | |
val f1 = { ()=> fib(n - 1) } | |
f1 fork | |
val f2 = { ()=> fib(n - 2) } | |
(f2 compute) + (f1 join) | |
} | |
val pool = new ForkJoinPool() | |
assert ((pool invoke { ()=> fib(1) }) == 1) | |
assert ((pool invoke { ()=> fib(2) }) == 1) | |
assert ((pool invoke { ()=> fib(3) }) == 2) | |
assert ((pool invoke { ()=> fib(4) }) == 3) | |
assert ((pool invoke { ()=> fib(5) }) == 5) | |
assert ((pool invoke { ()=> fib(6) }) == 8) | |
assert ((pool invoke { ()=> fib(7) }) == 13) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.fencepost.forkjoin | |
import jsr166y._ | |
import org.scalatest.Suite | |
class ForkJoinTestFailTwo extends Suite { | |
class Wrapper[T](somefunc:()=>T) extends RecursiveTask[T] { | |
override def compute = somefunc.apply | |
// RecursiveTask.compute() is protected and there's no obvious way to | |
// elevate it's access level within a Scala class definition. The type | |
// system (very correctly) doesn't allow a random function access to | |
// protected methods of a class even when that method is invoked by | |
// a method within the class itself. Defining a new method with standard | |
// access resolves the issue. | |
def surrogate = compute | |
} | |
implicit def fn2wrapper(fn:()=>Int):Wrapper[Int] = { | |
return new Wrapper[Int](fn) | |
} | |
def testFibonacci() = { | |
def fib(n:Int):Int = { | |
if (n <= 1) | |
return n | |
val f1 = { ()=> fib(n - 1) } | |
f1 fork | |
val f2 = { ()=> fib(n - 2) } | |
(f2 compute) + (f1 join) | |
} | |
val pool = new ForkJoinPool() | |
assert ((pool invoke { ()=> fib(1) }) == 1) | |
assert ((pool invoke { ()=> fib(2) }) == 1) | |
assert ((pool invoke { ()=> fib(3) }) == 2) | |
assert ((pool invoke { ()=> fib(4) }) == 3) | |
assert ((pool invoke { ()=> fib(5) }) == 5) | |
assert ((pool invoke { ()=> fib(6) }) == 8) | |
assert ((pool invoke { ()=> fib(7) }) == 13) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment