gpars howto - when to use which concurrency abstraction

48
GPars 'coz concurrency is Groovy Václav Pech

Post on 21-Oct-2014

1.511 views

Category:

Technology


0 download

DESCRIPTION

 

TRANSCRIPT

Page 1: GPars howto - when to use which concurrency abstraction

GPars

'coz concurrency is Groovy

Václav Pech

Page 2: GPars howto - when to use which concurrency abstraction

Asynchronous calculations

Fork/Join

Parallel collections

Actors

Agents, Stm

Dataflow

CSP

Why this talk?

Page 3: GPars howto - when to use which concurrency abstraction

StructureParallelism

Task Data

Random

Independent DependentHierarchical

Geometrical

Streamed

Event-driven

Functional

HierarchicalShared state

Page 4: GPars howto - when to use which concurrency abstraction

StructureParallelism

Task Data

Random

Independent DependentHierarchical

Geometrical

Streamed

Event-driven

Functional

HierarchicalShared state

Page 5: GPars howto - when to use which concurrency abstraction

ParallelismTask parallelism

Task Data

Random

Independent DependentHierarchical

Geometrical

Streamed

Event-driven

Functional

HierarchicalShared state

Page 6: GPars howto - when to use which concurrency abstraction

Asynchronous invocation

Future f = threadPool.submit(calculation);

System.out.println(“Result: “ + f.get());

Page 7: GPars howto - when to use which concurrency abstraction

Async the Groovy way

task {

calculation.process()

}

Page 8: GPars howto - when to use which concurrency abstraction

Async the Groovy way

def group = new NonDaemonPGroup(10)

group.task {

calculation.process()

}

Page 9: GPars howto - when to use which concurrency abstraction

group.task {->…}

group.task new Runnable() {…}

group.task new Callable<V>() {...}

Async the Groovy way

Page 10: GPars howto - when to use which concurrency abstraction

Independent tasks

def group = new NonDaemonPGroup(10)

submissions.each {form →

group.task {

form.process()

}

}

Page 11: GPars howto - when to use which concurrency abstraction

Dependent tasksParallelism

Task Data

Random

Independent DependentHierarchical

Geometrical

Streamed

Event-driven

Functional

HierarchicalShared state

Page 12: GPars howto - when to use which concurrency abstraction

State sharingParallelism

Task Data

Random

Independent DependentHierarchical

Geometrical

Streamed

Event-driven

Functional

HierarchicalShared state

Page 13: GPars howto - when to use which concurrency abstraction

State sharing

List registrations = []

submissions.each {form →

group.task {

if (form.process().valid) {

registrations << form

}

}

}

Page 14: GPars howto - when to use which concurrency abstraction

State sharing

List registrations = []

submissions.each {form →

group.task {

if (form.process().valid) {

registrations << form

}

}

}

Needs protection

Page 15: GPars howto - when to use which concurrency abstraction

Agent

Lock Shared Mutable State in a Safe

Alterthe

State

Alterthe

State

Page 16: GPars howto - when to use which concurrency abstraction

Agent inside

Double IncrementAdd 25

Message Queue

36 thread

Page 17: GPars howto - when to use which concurrency abstraction

Sharing through agents

Agent registrations = group.agent( [] )

submissions.each {form →

group.task {

if (form.process().valid) {

registrations.send {it << form}

}

}

}

Page 18: GPars howto - when to use which concurrency abstraction

Random task dependencyParallelism

Task Data

Random

Independent DependentHierarchical

Geometrical

Streamed

Event-driven

Functional

HierarchicalShared state

Page 19: GPars howto - when to use which concurrency abstraction

Dataflow Concurrency

No race-conditions

No live-locks

Deterministic deadlocks

Page 20: GPars howto - when to use which concurrency abstraction

Dataflow Variables / Promisesmain task2 task3

x

yz

task1

Page 21: GPars howto - when to use which concurrency abstraction

Dataflow Variables / Promisestask2

x

task1

Page 22: GPars howto - when to use which concurrency abstraction

Dataflow Variables / Promisesmain task2 task3

x

yz

task1

Page 23: GPars howto - when to use which concurrency abstraction

Chaining promises

def h1 = download('url') then {text → text.trim()} then hash

Page 24: GPars howto - when to use which concurrency abstraction

Error handling

url.then(download)

.then(calculateHash)

.then(formatResult)

.then(printResult, printError)

.then(sendNotificationEmail);

Page 25: GPars howto - when to use which concurrency abstraction

List registrations = []

List<Promise> forms=submissions.collect {form →

group.task {

if (form.process().valid) return form

}

}

forms.each{registrations << it.get()}

Pass results around

Page 26: GPars howto - when to use which concurrency abstraction

Dataflow Variables / Promisestask2

x

task1

Page 27: GPars howto - when to use which concurrency abstraction

Dataflow Channelstask2

x|y|z

task1

Page 28: GPars howto - when to use which concurrency abstraction

Synchronous Channelstask2

x|y|z

task1

Page 29: GPars howto - when to use which concurrency abstraction

Tasks with progress indication

List<Promise> forms=submissions.collect {form →

group.task {

def result = form.process()

progressQueue << 1

if (result.valid) {

return form

}

}

}

Page 30: GPars howto - when to use which concurrency abstraction

Channel Selection

Select alt = group.select(validForms, invalidForms)

SelectResult selectResult = alt.select() //alt.prioritySelect()

switch (selectResult.index) {

case 0: registrations << selectResult.value; break

case 1: ...

}

Page 31: GPars howto - when to use which concurrency abstraction

ParallelismData parallelism

Task Data

Random

Independent DependentHierarchical

Geometrical

Streamed

Event-driven

Functional

HierarchicalShared state

Page 32: GPars howto - when to use which concurrency abstraction

ParallelismData parallelism

Task Data

Random

Independent DependentHierarchical

Geometrical

Streamed

Event-driven

Functional

HierarchicalShared state

Page 33: GPars howto - when to use which concurrency abstraction

Geometric decomposition

images.eachParallel {it.process()}

documents.sumParallel()

candidates.maxParallel {it.salary}.marry()

Page 34: GPars howto - when to use which concurrency abstraction

Geometric decomposition

registrations = submissions

.collectParallel { form -> form.process()}

.findAllParallel { it.valid }

registrations = submissions.parallel

.map { form -> form.process()}

.filter { it.valid }.collection

Page 35: GPars howto - when to use which concurrency abstraction

Frequent confusion

Page 36: GPars howto - when to use which concurrency abstraction

Improper use 1

def accumulator = 0

myCollection.eachParallel {

accumulator += calculate(it)

}

Page 37: GPars howto - when to use which concurrency abstraction

Improper use 2

new File("/file.txt").withReader{reader ->

reader.eachParallel {

def r1 = step1(r)

def r2 = step2(r1)

def r3 = step3(r2)

}

}

Page 38: GPars howto - when to use which concurrency abstraction

Unroll iteration

def pipeline = data | step1 | step2 | step3

new File("/file.txt").withReader{reader ->

reader.each {

data << it

}

}

Page 39: GPars howto - when to use which concurrency abstraction

Unroll iteration

Page 40: GPars howto - when to use which concurrency abstraction

ParallelismStreamed data

Task Data

Random

Independent DependentHierarchical

Geometrical

Streamed

Event-driven

Functional

HierarchicalShared state

Page 41: GPars howto - when to use which concurrency abstraction

Pipeline DSL

def toProcess = new DataflowQueue()

def validated = new DataflowQueue()

toProcess | {form -> process(form)} |

{processedForm -> validate(processedForm)} | validated

submissions.each {toProcess << it}

Page 42: GPars howto - when to use which concurrency abstraction

Url resolverUrl resolverUrl resolverprocess

validate

inProcess

validated

Page 43: GPars howto - when to use which concurrency abstraction

Url resolverUrl resolver

Downloader

Groovy scanner Scala scanner

Url resolverUrl resolver

Reporter

Speculator

Evaluator

Splitter

Confirm

Cache updates

Approvals

Page 44: GPars howto - when to use which concurrency abstraction

Dataflow Operators

operator(inputs: [headers, bodies, footers],

outputs: [articles, summaries])

{header, body, footer ->

def article = buildArticle(header, body, footer)

bindOutput(0, article)

bindOutput(1, buildSummary(article))

}

Page 45: GPars howto - when to use which concurrency abstraction
Page 46: GPars howto - when to use which concurrency abstraction

ConclusionParallelism

Task Data

Random

Independent DependentHierarchical

Geometrical

Streamed

Event-driven

Functional

HierarchicalShared state

Page 47: GPars howto - when to use which concurrency abstraction

Summary

Parallelism is not hard, multi-threading is

Jon Kerridge, Napier University

Page 48: GPars howto - when to use which concurrency abstraction

Questions?

Find more at:http://gpars.codehaus.org

http://www.jroller.com/vaclav

http://twitter.com/vaclav_pech