Concurrency	Patterns	
In	Kotlin
Huynh	Quang	Thao	
Trusting		Social	
Google	Developer	Expert
Myself
- Nationality:	Vietnam	
- Company:	Trusting	Social	-	Eintech	company	provided	credit	score	for	unbanked	users.	
- Working:	Backend,	Infrastructure,	and	Mobile	(side	project)	
- Member	of	GDE	(Google	Developer	expert)	
- Blog:	https://medium.com/@huynhquangthao		
- StackOverFlow:	https://stackoverElow.com/users/1192728/hqt	(24,000	points	til	now)
Operating		System	threads
- Process	is	the	instance	of	a	computer	program	that	is	being	executed	
by	one	or	many	threads
Operating		System	threads
- Process	is	the	instance	of	a	computer	program	that	is	being	executed	
by	one	or	many	threads	
- Threads	are	spawn	from	the	process	that	they	share	the	same	memory	
space.
Operating		System	threads
- Process	is	the	instance	of	a	computer	program	that	is	being	executed	
by	one	or	many	threads	
- Threads	are	spawn	from	the	process	that	they	share	the	same	memory	
space.	
Context	Switching
Coroutines	
- Coroutines	are	very	similar	to	threads.		(100_000	coroutines	easily)
Coroutines	
- Coroutines	are	very	similar	to	threads.		(100_000	coroutines	easily)	
- Coroutines	are	cooperatively	multitasked.	This	means	that	coroutines	
provide	concurrency	but	not	parallelism.
Coroutines	
- Coroutines	are	very	similar	to	threads.		(100_000	coroutines	easily)	
- Coroutines	are	cooperatively	multitasked.	This	means	that	coroutines	
provide	concurrency	but	not	parallelism.	
- Switching	between	coroutines	need	not	involve	any	system	calls	or	
any	blocking	calls	whatsoever.
fun spawnThreads() {
repeat(100_000) {
thread {
sleep(1000)
print(".")
}
}
}
fun spawnCoroutine() = runBlocking {
repeat(100_000) {
// launch a lot of coroutines
launch {
delay(1000L)
print(".")
}
}
}
Concurrency	not	parallelism	
Scenario:	We	have	2	very	important	tasks	in	one	day:	
1.Get	a	passport	
2.Get	a	presentation	done
Concurrency	not	parallelism	
Scenario:	We	have	2	very	important	tasks	in	one	day:	
1.Get	a	passport	
2.Get	a	presentation	done
Solution	1:	Sequential	Execution	
- passport	ofEice	for	2	hours	
- wait	in	the	line	for	4	hours	get	the	task	done	
- drive	back	2	hours,	go	home		
- stay	awake	5	more	hours	and	get	presentation	done.	
Cost:	13	hours.
Concurrency	not	parallelism	
Scenario:	We	have	2	very	important	tasks	in	one	day:	
1.Get	a	passport	
2.Get	a	presentation	done
Solution	2:	Concurrency	Execution	
- passport	ofEice	for	2	hours	
- wait	in	the	line	for	4	hours.	Start	working	on	the	presentation.	
- drive	back	2	hours,	go	home		
- stay	awake	1	more	hours	and	get	presentation	done.	
Cost:	9	hours
Concurrency	not	parallelism	
Scenario:	We	have	2	very	important	tasks	in	one	day:	
1.Get	a	passport	
2.Get	a	presentation	done
Solution	3:	Parallel	Execution	
- passport	ofEice	for	2	hours	
- In	them	same	time,	assistant	works	on	the	presentation.	
- wait	in	the	line	for	4	hours.		
- drive	back	2	hours,	go	home		
- stay	awake	1	more	hours	and	get	presentation	done.	
Cost:	9	hours
Concurrency	not	parallelism	
Scenario:	We	have	2	very	important	tasks	in	one	day:	
1.Get	a	passport	
2.Get	a	presentation	done
Solution	4:	Concurrent	and	Parallel	
- passport	ofEice	for	2	hours	
- In	them	same	time,	assistant	works	on	the	presentation.	
- wait	in	the	line	for	4	hours.	Check	the	Eirst	draft	and	give	comments.	
- drive	back	2	hours,	go	home		
- stay	awake	15	minutes	more	hours	and	get	presentation	done.	
Cost:	6	hours	15	minutes
Concurrency	not	parallelism	
Scenario:	We	have	2	very	important	tasks	in	one	day:	
1.Get	a	passport	
2.Get	a	presentation	done
Looking	back:	
- Get	a	passport	and	get	a	presentation	are	jobs.	
- Waiting	at	the	line	is	I/O	time.	
- Manager	and	Secretary	are	CPU	computational	resources.
Concurrency	not	parallelism	
Scenario:	We	have	2	very	important	tasks	in	one	day:	
1.Get	a	passport	
2.Get	10	presentations	done
Concurrency	not	parallelism	
Scenario:	We	have	2	very	important	tasks	in	one	day:	
1.Get	a	passport	
2.Get	10	presentations	done
Solution:	
- Get	a	passport	on	one	coroutine.	
- Each	presentation	work	is	on	one	coroutine.	
- Communication	between	coroutines	using	channel.
Concurrency	not	parallelism	
Scenario:	We	have	2	very	important	tasks	in	one	day:	
1.Get	a	passport	
2.Get	10	presentations	done
Solution:	
- Get	a	passport	on	one	coroutine.	
- Each	presentation	work	is	on	one	coroutine.	
- Communication	between	coroutines	using	channel.
Environment:	
- CPU	with	1	core.	
- CPU	with	2	cores.	
- CPU	with	multiple	cores.	
-->	Abstract	the		thread	handling	behind.
Concurrency	not	parallelism	
Concurrency	is	about	dealing	with	lots	of	things	at	once.	
Parallelism	is	about	doing	lots	of	things	at	once.	
-->	Concurrency	is	about	structure,	parallelism	is	about	execution.
Concurrency	not	parallelism	
Concurrency	is	about	dealing	with	lots	of	things	at	once.	
Parallelism	is	about	doing	lots	of	things	at	once.	
-->	Concurrency	is	about	structure,	parallelism	is	about	execution.	
Concurrency	provides	a	way	to	structure	a	solution	to	solve	a	problem	
that	may	(but	not	necessarily)	be	parallelizable.
Concurrency	not	parallelism	
Concurrency	is	about	dealing	with	lots	of	things	at	once.	
Parallelism	is	about	doing	lots	of	things	at	once.	
-->	Concurrency	is	about	structure,	parallelism	is	about	execution.	
Concurrency	provides	a	way	to	structure	a	solution	to	solve	a	problem	
that	may	(but	not	necessarily)	be	parallelizable.	
Coroutine/channel	open	a	lot	of	chance	to	solve	concurrency	
problems.
Concurrency	Patterns
Pipelines
- A	pipeline	is	a	pattern	where	one	coroutine	is	producing,	possibly	inEinite,	
stream	of	values	
- A	pipeline	is	a	great	way	to	break	a	long	process	into	smaller	steps.
Pipelines
- A	pipeline	is	a	pattern	where	one	coroutine	is	producing,	possibly	inEinite,	
stream	of	values	
- A	pipeline	is	a	great	way	to	break	a	long	process	into	smaller	steps.
Pipelines
- A	pipeline	is	a	pattern	where	one	coroutine	is	producing,	possibly	inEinite,	
stream	of	values	
- A	pipeline	is	a	great	way	to	break	a	long	process	into	smaller	steps.
Pipelinesfun CoroutineScope.produceNumbers() = produce<Int> {
var x = 1
while (true) send(x++) // infinite stream of integers starting from 1
}
Pipelinesfun CoroutineScope.produceNumbers() = produce<Int> {
var x = 1
while (true) send(x++) // infinite stream of integers starting from 1
}
fun CoroutineScope.square(numbers: ReceiveChannel<Int>): ReceiveChannel<Int> = produce {
for (x in numbers) send(x * x)
}
Pipelinesfun CoroutineScope.produceNumbers() = produce<Int> {
var x = 1
while (true) send(x++) // infinite stream of integers starting from 1
}
fun CoroutineScope.square(numbers: ReceiveChannel<Int>): ReceiveChannel<Int> = produce {
for (x in numbers) send(x * x)
}
fun pipeline() = runBlocking {
val numbers = produceNumbers() // produces integers from 1 and on
val squares = square(numbers) // squares integers
for (i in 1..5) println(squares.receive()) // print first five
println("Done!") // we are done
coroutineContext.cancelChildren() // cancel children coroutines
}
Select	Expression
Select	expression	makes	it	possible	to	await	multiple	suspending	
functions	simultaneously	and	select	the	Eirst	one	that	becomes	available.	
Select	expressions	are	an	experimental	features.
Select	Expressionsuspend fun processJob(
streamOne: ReceiveChannel<String>,
streamSecond: ReceiveChannel<String>) {
while (true) {
select<Unit> {
streamOne.onReceive { value ->
println("stream-one -> '$value'")
}
streamSecond.onReceive { value ->
println("stream-second -> '$value'")
}
}
}
println("End")
}
stream-one -> 'one'
stream-second -> 'second'
stream-one -> 'one'
stream-one -> 'one'
stream-second -> 'second'
stream-one -> 'one'
stream-second -> 'second'
stream-one -> 'one'
stream-second -> 'second'
stream-one -> 'one'
stream-second -> 'second'
stream-one -> 'one'
stream-one -> 'one'
stream-one -> 'one'
Unbiased	Select
Select	is	inherently	biased.	If	two	events	happen	at	the	same	time,	it	
will	select	the	Eirst	clause.
val repeats = 10_000
val p1 = producer("A", repeats)
val p2 = producer("B", repeats)
val p3 = producer("C", repeats)
val results = ConcurrentHashMap<String, Int>()
repeat(repeats) {
val result = select<String> {
p1.onReceive { it }
p2.onReceive { it }
p3.onReceive { it }
}
results.compute(result) { k, v ->
if (v == null) {
1
} else {
v + 1
}
}
}
println(results)
{A=8235, B=1620, C=145}
{A=7850, B=2062, C=88}
{A=7878, B=2002, C=120}
{A=8260, B=1648, C=92}
{A=7927, B=2011, C=62}
val repeats = 10_000
val p1 = producer("A", repeats)
val p2 = producer("B", repeats)
val p3 = producer("C", repeats)
val results = ConcurrentHashMap<String, Int>()
repeat(repeats) {
val result = selectUnbiased<String> {
p1.onReceive { it }
p2.onReceive { it }
p3.onReceive { it }
}
results.compute(result) { k, v ->
if (v == null) {
1
} else {
v + 1
}
}
}
println(results)
{A=3336, B=3327, C=3337}
{A=3330, B=3332, C=3338}
{A=3334, B=3333, C=3333}
{A=3334, B=3336, C=3330}
{A=3332, B=3335, C=3333}
Selecting	on	close
val p1 = produce {
repeat(10) {
send("A")
}
}
val p2 = produce {
repeat(5) {
send("B")
}
}
runBlocking {
repeat(15) {
val result = selectUnbiased<String> {
p1.onReceive {
it
}
p2.onReceive {
it
}
}
println(result)
}
}
Selecting	on	close
val p1 = produce {
repeat(10) {
send("A")
}
}
val p2 = produce {
repeat(5) {
send("B")
}
}
runBlocking {
repeat(15) {
val result = selectUnbiased<String> {
p1.onReceiveOrNull {
it
}
p2.onReceiveOrNull {
it
}
}
println(result)
}
}
Done	Channel
When	parent	objects	are		closed	and	they	don't	have	coroutine	objects	
which	stored	in	the	children	layer.
App
Scheduler
Jobs		Manager
List	Coroutines
Done	Channel
When	parent	objects	are		closed	and	they	don't	have	coroutine	objects	
which	stored	in	the	children	layer.
App
Scheduler
Jobs		Manager
List	Coroutines
Close	()
Close	()
Close	()
app.Close	()
Solution	1	
Add	the	close	
function		to	
every	object
Done	Channel
When	parent	objects	are		closed	and	they	don't	have	coroutine	objects	
which	stored	in	the	children	layer.
App
Scheduler
Jobs		Manager
List	Coroutines
Solution	2	
send	the	close	
signal	directly	to	
all	coroutines
Please	close	for	me	:	)
Done	Channel
suspend fun processJob(
streamOne: ReceiveChannel<String>,
streamSecond: ReceiveChannel<String>) {
while (true) {
selectUnbiased<Unit> {
streamOne.onReceive { value ->
println("stream-one -> '$value'")
}
streamSecond.onReceive { value ->
println("stream-second -> '$value'")
}
}
}
println("End")
}
suspend fun processJob(
streamOne: ReceiveChannel<String>,
streamSecond: ReceiveChannel<String>,
done: Channel<Boolean>
) {
var run = true
while (run) {
selectUnbiased<Unit> {
done.onReceive {
run = false
}
streamOne.onReceive { value ->
println("stream-one -> '$value'")
}
streamSecond.onReceive { value ->
println("stream-second -> '$value'")
}
}
}
println("End")
}
val done = Channel<Boolean>()
val streamOne = streamOne()
val streamSecond = streamSecond()
val job = launch {
processJob(streamOne, streamSecond, done)
}
delay(2000)
println("Stop the job")
done.send(true)
streamOne.cancel()
streamSecond.cancel()
Tee	channel
Sometimes	we	may	want	to	split	values	coming	in	from	a	channel	so	that	
you	can	send	them	off	into	two	separate	areas	of	your	codebase.	
	Example:	we	want	to	take	in	a	stream	of	user	commands	on	a	channel,	
send	them	to	something	that	executes	them,	and	also	send	them	to	
something	that	logs	the	commands	for	later	auditing.
suspend fun tee(
stream: ReceiveChannel<String>,
done: Channel<Boolean>
): Pair<ReceiveChannel<String>, ReceiveChannel<String>> {
val out1 = Channel<String>()
val out2 = Channel<String>()
launch {
var run = true
try {
while (run) {
done.poll()?.let {
run = false
} ?: stream.poll()?.let {
out1.send(it)
out2.send(it)
}
}
} finally {
out1.close()
out2.close()
}
}
return Pair(out1, out2)
}
Others
Fan-in	Fan-out	pattern	
OrDone	channel	
Bridge	channel	
Mutex	
....
Summary
- Coroutine	provides	the	concurrency.	
- We	compose	small	patterns	into	the	larger	one.	
- Reusable	and	composable.
Q&A

Concurrency pattern in Kotlin