Petra Bierleutgeb
@pbvie
...and we don't like waiting
The term Concurrency refers to techniques that make programs more usable. If you can load multiple documents simultaneously in the tabs of your browser and you can still open menus and perform other actions, this is concurrency.
https://wiki.haskell.org/Parallelism_vs._Concurrency
The term Parallelism refers to techniques to make programs faster by performing several computations at the same time. This requires hardware with multiple processing units.
https://wiki.haskell.org/Parallelism_vs._Concurrency
"An asynchronous operation is an operation which continues in the background after being initiated, without forcing the caller to wait for it to finish before running other code."
https://blog.slaks.net/2014-12-23/parallelism-async-threading-explained/
Motivation and Responsibilities
decouple implementation logic from execution logic
trait ExecutionContext {
def execute(runnable: Runnable): Unit
def reportFailure(cause: Throwable): Unit
}
a.k.a. Scala's default ExecutionContext
def doSomethingAsync()(ec: ExecutionContext): Future[Int] = ...
implicit val ec: ExecutionContext = ExecutionContext.global
Future.traverse(1 to 25)(i => doSomethingAsync())
it depends!
scala.concurrent.context.minThreads = 1
scala.concurrent.context.numThreads = "x1"
scala.concurrent.context.maxThreads = "x1"
scala.concurrent.context.maxExtraThreads = 256
def slowOp(a: Int, b: Int)(implicit ec: ExecutionContext): Future[Int] = Future {
logger.debug("slowOp")
Thread.sleep(80)
a + b
}
def combined(a: Int, b: Int)(implicit ec: ExecutionContext): Future[Int] = {
val seqF = for (i <- 1 to 100) yield slowOp(a + i, b + i + 1)
Future.sequence(seqF).map(_.sum)
}
0.950 ops/s
[DEBUG] Thread[20,scala-execution-context-global-20,5] - slowOp {}
[DEBUG] Thread[18,scala-execution-context-global-18,5] - slowOp {}
[DEBUG] Thread[15,scala-execution-context-global-15,5] - slowOp {}
[DEBUG] Thread[17,scala-execution-context-global-17,5] - slowOp {}
[DEBUG] Thread[22,scala-execution-context-global-22,5] - slowOp {}
[DEBUG] Thread[16,scala-execution-context-global-16,5] - slowOp {}
[DEBUG] Thread[19,scala-execution-context-global-19,5] - slowOp {}
[DEBUG] Thread[21,scala-execution-context-global-21,5] - slowOp {}
[DEBUG] Thread[18,scala-execution-context-global-18,5] - slowOp {}
[DEBUG] Thread[15,scala-execution-context-global-15,5] - slowOp {}
[DEBUG] Thread[20,scala-execution-context-global-20,5] - slowOp {}
[DEBUG] Thread[17,scala-execution-context-global-17,5] - slowOp {}
[DEBUG] Thread[16,scala-execution-context-global-16,5] - slowOp {}
def slowOpBlocking(a: Int, b: Int)(implicit ec: ExecutionContext): Future[Int] = Future {
logger.debug("slowOpBlocking")
blocking {
Thread.sleep(80)
}
a + b
}
def combined(a: Int, b: Int)(implicit ec: ExecutionContext): Future[Int] = {
val seqF = for (i <- 1 to 100) yield slowOpBlocking(a + i, b + i + 1)
Future.sequence(seqF).map(_.sum)
}
6.861 ops/s
...
[DEBUG] Thread[3177,scala-execution-context-global-3177,5] - slowOpBlocking {}
[DEBUG] Thread[3178,scala-execution-context-global-3178,5] - slowOpBlocking {}
[DEBUG] Thread[3179,scala-execution-context-global-3179,5] - slowOpBlocking {}
[DEBUG] Thread[3180,scala-execution-context-global-3180,5] - slowOpBlocking {}
[DEBUG] Thread[3181,scala-execution-context-global-3181,5] - slowOpBlocking {}
[DEBUG] Thread[3182,scala-execution-context-global-3182,5] - slowOpBlocking {}
[DEBUG] Thread[3183,scala-execution-context-global-3183,5] - slowOpBlocking {}
[DEBUG] Thread[3184,scala-execution-context-global-3184,5] - slowOpBlocking {}
...
Slides and further reading
coming soon
(will be posted on meetup.com)