-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b63a154
commit dbce67b
Showing
6 changed files
with
160 additions
and
1 deletion.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
plugins { | ||
kotlin("jvm") | ||
} | ||
|
||
dependencies { | ||
implementation(kotlin("stdlib-jdk8")) | ||
compile("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1") | ||
} |
47 changes: 47 additions & 0 deletions
47
coroutines/src/main/java/io/mfj/kotlinnight/coroutines/FanOut.kt
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package io.mfj.kotlinnight.coroutines | ||
|
||
import kotlinx.coroutines.* | ||
import kotlinx.coroutines.channels.* | ||
import java.util.* | ||
|
||
// Lets look through a more real example | ||
|
||
// We have a source of things. In this case, integers 0 - 1000 | ||
|
||
// We need to process each one, and want to use 10 workers to do it. | ||
|
||
fun main() = runBlocking { | ||
|
||
val workerCount = 10 | ||
|
||
val source = (0..1000).asSequence() | ||
|
||
// Create a channel that we can receive items from. | ||
val channel = produce { | ||
source.forEach { | ||
send(it) | ||
} | ||
} | ||
|
||
(0 until workerCount) | ||
.forEach { worker -> | ||
// launch a worker to read items from the channel and process them. | ||
launch { | ||
for ( item in channel ) { | ||
process(worker,item) | ||
} | ||
} | ||
} | ||
|
||
} | ||
|
||
val rand = Random() | ||
|
||
fun process(worker:Int,item:Int) { | ||
Thread.sleep( rand.nextInt(10).toLong() ) | ||
println("[${worker}] ${item}") | ||
} | ||
|
||
// send is the suspension point. Every time send is called, | ||
// that is the end of the continuation, and the dispatcher | ||
// can switch to another coroutine. |
13 changes: 13 additions & 0 deletions
13
coroutines/src/main/java/io/mfj/kotlinnight/coroutines/HowItWorks.kt
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package io.mfj.kotlinnight.coroutines | ||
|
||
// How do we cooperate so it can switch processes? | ||
|
||
// The compiler turns every block between suspension points into a Continuation. | ||
// It keeps track of where in a suspension function progress is, | ||
// so it can suspend and switch to another coroutine and then come back | ||
// and find the continuation and restart. | ||
// Instead of a thread context switch, it is running a switch statement. | ||
|
||
// See: | ||
// Deep Dive into Coroutines on JVM by RomanElizarov | ||
// https://www.youtube.com/watch?v=YrrUCSi72E8 |
74 changes: 74 additions & 0 deletions
74
coroutines/src/main/java/io/mfj/kotlinnight/coroutines/Intro.kt
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package io.mfj.kotlinnight.coroutines | ||
|
||
import kotlinx.coroutines.* | ||
|
||
// We have 8 and 16 core computers. | ||
// Let's use them. | ||
|
||
// The old way - fire up a bunch of threads. | ||
// Thread creation and switching is expensive. | ||
// If you have 10 or 100 threads you are okay. 1000, 10000 threads is not going to perform well. | ||
// Threaded parallelism spends a lot of time blocking. | ||
|
||
// Coroutines lets us parallelize many processes without using more threads than we have cores. | ||
// The coroutine dispatchers sets up a thead pool, and we can use that dispatcher for multiple thingss. | ||
|
||
// With Threads, we rely on the OS to forcibly switch us out. | ||
// With coroutines, we cooperate. | ||
|
||
// suspend keyword means the function does not return immediately | ||
suspend fun getToken(): String { | ||
// hit some backend | ||
return "abcdefd" | ||
} | ||
|
||
suspend fun post( body:String ): String { | ||
val token = getToken() // async | ||
val result = doPost( token, body ) // async | ||
return result | ||
} | ||
|
||
fun doPost( token:String, body:String ): String { | ||
// hit some backend | ||
return """{"result":"success"}""" | ||
} | ||
|
||
// Where is the suspending actually happening? | ||
// look for the little marks in the IDE | ||
|
||
// we can do normal things like loops and exception handling. | ||
suspend fun makeRequests() { | ||
(0..3).forEach { | ||
try { | ||
val response = post( "request ${it}" ) | ||
println(response) | ||
} catch ( e:Exception ) { | ||
e.printStackTrace() | ||
} | ||
} | ||
} | ||
|
||
// You cannot call a suspending function from a non-suspended context | ||
// Try removing "suspend" from makeRequests | ||
|
||
// How do we call a suspending function? | ||
|
||
// Use coroutine builders | ||
|
||
fun main() { | ||
// launch starts a coroutine scope in the GlobalScope coroutine dispatcher. | ||
// This is where the forking happens. | ||
val job:Job = GlobalScope.launch { | ||
makeRequests() | ||
} | ||
println("hello") | ||
runBlocking { | ||
job.join() | ||
} | ||
println( "done" ) | ||
} | ||
|
||
// For more in-depth, see Roman Elizarov's presentations at KotlinConf: | ||
// https://www.youtube.com/watch?v=_hfBv0a09Jc | ||
// https://www.youtube.com/watch?v=a3agLJQ6vt8 | ||
// Watch both before you try to write any code - some stuff showed in the first one changed before 1.0 |
16 changes: 16 additions & 0 deletions
16
coroutines/src/main/java/io/mfj/kotlinnight/coroutines/LightWeighThreads.kt
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package io.mfj.kotlinnight.coroutines | ||
|
||
import kotlinx.coroutines.* | ||
|
||
// a million threads would be a problem. | ||
// we can do a million jobs in a coroutine no problem. | ||
fun main() = runBlocking { | ||
val jobs = List(100_000) { | ||
launch { | ||
delay(1000) // suspend for 1 second | ||
print(".") | ||
} | ||
} | ||
jobs.forEach { it.join() } | ||
println("done") | ||
} |
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