Created
August 29, 2012 22:57
-
-
Save Narigo/3519989 to your computer and use it in GitHub Desktop.
Scala ways to handle event based stuff?
This file contains 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 com.campudus.scalasnippets | |
import actors.Actor._ | |
import java.util.concurrent.atomic.AtomicInteger | |
import scala.annotation.tailrec | |
object SomeAsyncTests { | |
def asyncFunction(i: Int)(doWhenDone: => Unit) = actor { | |
println("doing stuff " + i) | |
Thread.sleep(1) | |
doWhenDone | |
} | |
// The type signatures could probably be optimized somehow... | |
def asyncToSync(cleanup: => Unit)(stuffToDo: (((=> Unit) => Unit) => Unit) => Unit) = { | |
val counter = new AtomicInteger(0) | |
var done = false | |
def synchronizer(fn: (=> Unit) => Unit) = { | |
// Count up, to remember to wait for another function to finish. | |
counter.incrementAndGet() | |
// Invoke the function we are waiting for | |
fn({ | |
// When the function finishes, the counter needs to know it's done. | |
// If the whole block of functions is ready, it's time for the cleanup. | |
if (counter.decrementAndGet == 0 && done) { | |
cleanup | |
} | |
}) | |
} | |
stuffToDo(synchronizer) | |
done = true | |
// If all functions finished already, clean up! | |
if (counter.get == 0) { | |
cleanup | |
} | |
} | |
def main(args: Array[String]): Unit = { | |
val i = new AtomicInteger(0) | |
val numberOfAsyncFuns = 200 | |
def cleanup(s: String) = { println("cleanup " + s) } | |
// A) async | |
// The "usual" event-based way, call a method after work was done | |
// Con: You need to keep track of the number of async-functions you invoke | |
val counter = new AtomicInteger(numberOfAsyncFuns) | |
for (x <- 1 to numberOfAsyncFuns) { | |
val funNumber = i.incrementAndGet | |
println("starting " + funNumber + " in A)") | |
asyncFunction(funNumber) { | |
if (counter.decrementAndGet == 0) { | |
cleanup("A") | |
} | |
} | |
} | |
// B) async | |
// Another way, trying to keep track of the functions for you | |
// Con: You need to wrap every function call in a "sync()" block | |
asyncToSync(cleanup("B")) { | |
sync => | |
for (x <- 1 to numberOfAsyncFuns) { | |
val funNumber = i.incrementAndGet | |
println("starting " + funNumber + " in B)") | |
sync(asyncFunction(funNumber)) | |
} | |
} | |
// are there other/better ways of doing that? | |
// C) sync way of chaining functions | |
asyncFunction(i.incrementAndGet) { | |
asyncFunction(i.incrementAndGet) { | |
asyncFunction(i.incrementAndGet) { | |
asyncFunction(i.incrementAndGet) { | |
asyncFunction(i.incrementAndGet) { | |
cleanup("C") | |
} | |
} | |
} | |
} | |
} | |
// D) like C | |
def afterEachOther(c: Int): Unit = c match { | |
case 1 => asyncFunction(i.incrementAndGet)(cleanup("D")) | |
case x => asyncFunction(i.incrementAndGet)(afterEachOther(c - 1)) | |
} | |
afterEachOther(numberOfAsyncFuns) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment