commit
6014964885
60 changed files with 2052 additions and 0 deletions
-
5.gitignore
-
9README.md
-
37build.gradle
-
BINgradle/wrapper/gradle-wrapper.jar
-
6gradle/wrapper/gradle-wrapper.properties
-
172gradlew
-
84gradlew.bat
-
2settings.gradle
-
31src/main/kotlin/chapter1/section1/lightweight.kt
-
87src/main/kotlin/chapter1/section2/introduction-to-concurrency.kt
-
18src/main/kotlin/chapter1/section3/cpu-bound.kt
-
23src/main/kotlin/chapter1/section4/atomicity-violation.kt
-
26src/main/kotlin/chapter1/section4/deadlock.kt
-
22src/main/kotlin/chapter1/section4/race-condition.kt
-
29src/main/kotlin/chapter1/section5/explicit.kt
-
33src/main/kotlin/chapter1/section5/readable.kt
-
36src/main/kotlin/chapter2/async/async.kt
-
20src/main/kotlin/chapter2/dispatcher/launch.kt
-
23src/main/kotlin/chapter2/launch/launch.kt
-
31src/main/kotlin/chapter3/deferred/deferred.kt
-
20src/main/kotlin/chapter3/deferred/exception/deferred-unwrapped-exception.kt
-
20src/main/kotlin/chapter3/deferred/exception/deferred-wrapped-exception.kt
-
28src/main/kotlin/chapter3/finalstate/job-final-state.kt
-
19src/main/kotlin/chapter3/job/cancellation/cancel.kt
-
20src/main/kotlin/chapter3/job/cancellation/withcause/cancel-with-cause.kt
-
18src/main/kotlin/chapter3/job/job.kt
-
17src/main/kotlin/chapter3/job/lazy/join/join-start.kt
-
16src/main/kotlin/chapter3/job/lazy/lazy.kt
-
17src/main/kotlin/chapter3/job/lazy/start/lazy-start.kt
-
29src/main/kotlin/chapter4/client/deferred/deferred-impl.kt
-
28src/main/kotlin/chapter4/client/suspending/suspend-impl.kt
-
59src/main/kotlin/chapter4/context/dispatcher/dispatcher.kt
-
20src/main/kotlin/chapter4/context/exception/exception-handling.kt
-
22src/main/kotlin/chapter4/context/mix/join/join.kt
-
25src/main/kotlin/chapter4/context/mix/separate/separate.kt
-
76src/main/kotlin/chapter4/context/noncancellable/noncancellable.kt
-
28src/main/kotlin/chapter4/context/switch/switch.kt
-
15src/main/kotlin/chapter4/suspending/suspending.kt
-
103src/main/kotlin/chapter5/iterator/examples.kt
-
23src/main/kotlin/chapter5/iterator/fibonacci/fibonacci-iterator.kt
-
101src/main/kotlin/chapter5/producer/examples.kt
-
31src/main/kotlin/chapter5/producer/fibonacci/fibonacci.kt
-
82src/main/kotlin/chapter5/sequence/examples.kt
-
30src/main/kotlin/chapter5/sequence/fibonacci/sequence.kt
-
29src/main/kotlin/chapter6/buffered/array/array.kt
-
26src/main/kotlin/chapter6/buffered/conflated/conflated.kt
-
24src/main/kotlin/chapter6/buffered/linked/linked.kt
-
36src/main/kotlin/chapter6/interaction/receive/receive.kt
-
70src/main/kotlin/chapter6/interaction/send/send.kt
-
29src/main/kotlin/chapter6/unbufffered/rendezvous/rendezvous.kt
-
29src/main/kotlin/chapter7/actor/actor.kt
-
25src/main/kotlin/chapter7/actor/actorCounter.kt
-
46src/main/kotlin/chapter7/actor/interaction/actor_samples.kt
-
24src/main/kotlin/chapter7/atomic/atomic.kt
-
23src/main/kotlin/chapter7/atomicity/atomicity_violation.kt
-
26src/main/kotlin/chapter7/confinement/thread-confinement.kt
-
50src/main/kotlin/chapter7/mutex/interaction/mutex_interaction.kt
-
30src/main/kotlin/chapter7/mutex/mutex.kt
-
21src/main/kotlin/chapter7/volatile/using/volatile.kt
-
23src/main/kotlin/chapter7/volatile/volatile.kt
@ -0,0 +1,5 @@ |
|||
.DS_Store |
|||
.gradle/ |
|||
.idea/ |
|||
build/ |
|||
out |
@ -0,0 +1,9 @@ |
|||
# Learning Concurrency in Kotlin - Code Examples |
|||
|
|||
This repository contains the code examples for the book Learning Concurrency in Kotlin, written by yours truly and published by Packt. You can find more information about the book [here](https://www.packtpub.com/application-development/learning-concurrency-kotlin). |
|||
|
|||
Each chapter is divided in its own package, and each package contains all the examples that match the topics covered in the book. |
|||
|
|||
## Important |
|||
Notice that the code for the RSS Reader written throughout the book can be found [here](http://git.starcarr.co/). This repo contains all the examples that aren't part of that application. |
|||
|
@ -0,0 +1,37 @@ |
|||
group 'co.starcarr' |
|||
version '1.0-SNAPSHOT' |
|||
|
|||
buildscript { |
|||
ext.kotlin_version = '1.2.50' |
|||
ext.coroutines_version = '0.23.3' |
|||
|
|||
repositories { |
|||
mavenCentral() |
|||
} |
|||
dependencies { |
|||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" |
|||
} |
|||
} |
|||
|
|||
apply plugin: 'kotlin' |
|||
|
|||
repositories { |
|||
mavenCentral() |
|||
} |
|||
|
|||
dependencies { |
|||
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" |
|||
compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" |
|||
} |
|||
|
|||
compileKotlin { |
|||
kotlinOptions.jvmTarget = "1.8" |
|||
} |
|||
compileTestKotlin { |
|||
kotlinOptions.jvmTarget = "1.8" |
|||
} |
|||
kotlin { |
|||
experimental { |
|||
coroutines "enable" |
|||
} |
|||
} |
@ -0,0 +1,6 @@ |
|||
#Thu Dec 07 21:32:20 PST 2017 |
|||
distributionBase=GRADLE_USER_HOME |
|||
distributionPath=wrapper/dists |
|||
zipStoreBase=GRADLE_USER_HOME |
|||
zipStorePath=wrapper/dists |
|||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-rc-2-all.zip |
@ -0,0 +1,172 @@ |
|||
#!/usr/bin/env sh |
|||
|
|||
############################################################################## |
|||
## |
|||
## Gradle start up script for UN*X |
|||
## |
|||
############################################################################## |
|||
|
|||
# Attempt to set APP_HOME |
|||
# Resolve links: $0 may be a link |
|||
PRG="$0" |
|||
# Need this for relative symlinks. |
|||
while [ -h "$PRG" ] ; do |
|||
ls=`ls -ld "$PRG"` |
|||
link=`expr "$ls" : '.*-> \(.*\)$'` |
|||
if expr "$link" : '/.*' > /dev/null; then |
|||
PRG="$link" |
|||
else |
|||
PRG=`dirname "$PRG"`"/$link" |
|||
fi |
|||
done |
|||
SAVED="`pwd`" |
|||
cd "`dirname \"$PRG\"`/" >/dev/null |
|||
APP_HOME="`pwd -P`" |
|||
cd "$SAVED" >/dev/null |
|||
|
|||
APP_NAME="Gradle" |
|||
APP_BASE_NAME=`basename "$0"` |
|||
|
|||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
|||
DEFAULT_JVM_OPTS="" |
|||
|
|||
# Use the maximum available, or set MAX_FD != -1 to use that value. |
|||
MAX_FD="maximum" |
|||
|
|||
warn ( ) { |
|||
echo "$*" |
|||
} |
|||
|
|||
die ( ) { |
|||
echo |
|||
echo "$*" |
|||
echo |
|||
exit 1 |
|||
} |
|||
|
|||
# OS specific support (must be 'true' or 'false'). |
|||
cygwin=false |
|||
msys=false |
|||
darwin=false |
|||
nonstop=false |
|||
case "`uname`" in |
|||
CYGWIN* ) |
|||
cygwin=true |
|||
;; |
|||
Darwin* ) |
|||
darwin=true |
|||
;; |
|||
MINGW* ) |
|||
msys=true |
|||
;; |
|||
NONSTOP* ) |
|||
nonstop=true |
|||
;; |
|||
esac |
|||
|
|||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar |
|||
|
|||
# Determine the Java command to use to start the JVM. |
|||
if [ -n "$JAVA_HOME" ] ; then |
|||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then |
|||
# IBM's JDK on AIX uses strange locations for the executables |
|||
JAVACMD="$JAVA_HOME/jre/sh/java" |
|||
else |
|||
JAVACMD="$JAVA_HOME/bin/java" |
|||
fi |
|||
if [ ! -x "$JAVACMD" ] ; then |
|||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME |
|||
|
|||
Please set the JAVA_HOME variable in your environment to match the |
|||
location of your Java installation." |
|||
fi |
|||
else |
|||
JAVACMD="java" |
|||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
|||
|
|||
Please set the JAVA_HOME variable in your environment to match the |
|||
location of your Java installation." |
|||
fi |
|||
|
|||
# Increase the maximum file descriptors if we can. |
|||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then |
|||
MAX_FD_LIMIT=`ulimit -H -n` |
|||
if [ $? -eq 0 ] ; then |
|||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then |
|||
MAX_FD="$MAX_FD_LIMIT" |
|||
fi |
|||
ulimit -n $MAX_FD |
|||
if [ $? -ne 0 ] ; then |
|||
warn "Could not set maximum file descriptor limit: $MAX_FD" |
|||
fi |
|||
else |
|||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" |
|||
fi |
|||
fi |
|||
|
|||
# For Darwin, add options to specify how the application appears in the dock |
|||
if $darwin; then |
|||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" |
|||
fi |
|||
|
|||
# For Cygwin, switch paths to Windows format before running java |
|||
if $cygwin ; then |
|||
APP_HOME=`cygpath --path --mixed "$APP_HOME"` |
|||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` |
|||
JAVACMD=`cygpath --unix "$JAVACMD"` |
|||
|
|||
# We build the pattern for arguments to be converted via cygpath |
|||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` |
|||
SEP="" |
|||
for dir in $ROOTDIRSRAW ; do |
|||
ROOTDIRS="$ROOTDIRS$SEP$dir" |
|||
SEP="|" |
|||
done |
|||
OURCYGPATTERN="(^($ROOTDIRS))" |
|||
# Add a user-defined pattern to the cygpath arguments |
|||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then |
|||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" |
|||
fi |
|||
# Now convert the arguments - kludge to limit ourselves to /bin/sh |
|||
i=0 |
|||
for arg in "$@" ; do |
|||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` |
|||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option |
|||
|
|||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition |
|||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` |
|||
else |
|||
eval `echo args$i`="\"$arg\"" |
|||
fi |
|||
i=$((i+1)) |
|||
done |
|||
case $i in |
|||
(0) set -- ;; |
|||
(1) set -- "$args0" ;; |
|||
(2) set -- "$args0" "$args1" ;; |
|||
(3) set -- "$args0" "$args1" "$args2" ;; |
|||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; |
|||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; |
|||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; |
|||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; |
|||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; |
|||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; |
|||
esac |
|||
fi |
|||
|
|||
# Escape application args |
|||
save ( ) { |
|||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done |
|||
echo " " |
|||
} |
|||
APP_ARGS=$(save "$@") |
|||
|
|||
# Collect all arguments for the java command, following the shell quoting and substitution rules |
|||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" |
|||
|
|||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong |
|||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then |
|||
cd "$(dirname "$0")" |
|||
fi |
|||
|
|||
exec "$JAVACMD" "$@" |
@ -0,0 +1,84 @@ |
|||
@if "%DEBUG%" == "" @echo off |
|||
@rem ########################################################################## |
|||
@rem |
|||
@rem Gradle startup script for Windows |
|||
@rem |
|||
@rem ########################################################################## |
|||
|
|||
@rem Set local scope for the variables with windows NT shell |
|||
if "%OS%"=="Windows_NT" setlocal |
|||
|
|||
set DIRNAME=%~dp0 |
|||
if "%DIRNAME%" == "" set DIRNAME=. |
|||
set APP_BASE_NAME=%~n0 |
|||
set APP_HOME=%DIRNAME% |
|||
|
|||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. |
|||
set DEFAULT_JVM_OPTS= |
|||
|
|||
@rem Find java.exe |
|||
if defined JAVA_HOME goto findJavaFromJavaHome |
|||
|
|||
set JAVA_EXE=java.exe |
|||
%JAVA_EXE% -version >NUL 2>&1 |
|||
if "%ERRORLEVEL%" == "0" goto init |
|||
|
|||
echo. |
|||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. |
|||
echo. |
|||
echo Please set the JAVA_HOME variable in your environment to match the |
|||
echo location of your Java installation. |
|||
|
|||
goto fail |
|||
|
|||
:findJavaFromJavaHome |
|||
set JAVA_HOME=%JAVA_HOME:"=% |
|||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe |
|||
|
|||
if exist "%JAVA_EXE%" goto init |
|||
|
|||
echo. |
|||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% |
|||
echo. |
|||
echo Please set the JAVA_HOME variable in your environment to match the |
|||
echo location of your Java installation. |
|||
|
|||
goto fail |
|||
|
|||
:init |
|||
@rem Get command-line arguments, handling Windows variants |
|||
|
|||
if not "%OS%" == "Windows_NT" goto win9xME_args |
|||
|
|||
:win9xME_args |
|||
@rem Slurp the command line arguments. |
|||
set CMD_LINE_ARGS= |
|||
set _SKIP=2 |
|||
|
|||
:win9xME_args_slurp |
|||
if "x%~1" == "x" goto execute |
|||
|
|||
set CMD_LINE_ARGS=%* |
|||
|
|||
:execute |
|||
@rem Setup the command line |
|||
|
|||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar |
|||
|
|||
@rem Execute Gradle |
|||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% |
|||
|
|||
:end |
|||
@rem End local scope for the variables with windows NT shell |
|||
if "%ERRORLEVEL%"=="0" goto mainEnd |
|||
|
|||
:fail |
|||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of |
|||
rem the _cmd.exe /c_ return code! |
|||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 |
|||
exit /b 1 |
|||
|
|||
:mainEnd |
|||
if "%OS%"=="Windows_NT" endlocal |
|||
|
|||
:omega |
@ -0,0 +1,2 @@ |
|||
rootProject.name = 'learning-concurrency-in-kotlin' |
|||
|
@ -0,0 +1,31 @@ |
|||
package chapter1.section1 |
|||
|
|||
import kotlinx.coroutines.experimental.Job |
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.launch |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
import kotlin.system.measureTimeMillis |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
println("${Thread.activeCount()} threads active at the start") |
|||
val time = measureTimeMillis { |
|||
createCoroutines(3) |
|||
} |
|||
println("${Thread.activeCount()} threads active at end") |
|||
println("Took $time ms") |
|||
} |
|||
|
|||
suspend fun createCoroutines(amount: Int) { |
|||
val jobs = ArrayList<Job>() |
|||
for (i in 1..amount) { |
|||
jobs.add(launch { |
|||
println("Started $i in ${Thread.currentThread().name}") |
|||
delay(1000) |
|||
|
|||
println("Finished $i in ${Thread.currentThread().name}") |
|||
}) |
|||
} |
|||
jobs.onEach { |
|||
it.join() |
|||
} |
|||
} |
@ -0,0 +1,87 @@ |
|||
package chapter1.section2 |
|||
|
|||
import kotlinx.coroutines.experimental.async |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
import kotlin.system.measureTimeMillis |
|||
|
|||
class Profile(userInfo: UserInfo, contactInfo: ContactInfo) |
|||
class UserInfo(name:String, lastName: String) |
|||
class ContactInfo(address: String, zipCode: Int) |
|||
|
|||
// Example of a sequential implementation, where getUserInfo blocks |
|||
// the thread to do an IO operation |
|||
class Sequential { |
|||
fun getProfile(id: Int): Profile { |
|||
val basicUserInfo = getUserInfo(id) |
|||
val contactInfo = getContactInfo(id) |
|||
|
|||
return createProfile(basicUserInfo, contactInfo) |
|||
} |
|||
|
|||
private fun getUserInfo(id: Int): UserInfo { |
|||
// Block the thread for one second |
|||
// to simulate a service call |
|||
Thread.sleep(1000) |
|||
|
|||
return UserInfo("Susan", "Calvin") |
|||
} |
|||
|
|||
private fun getContactInfo(id: Int): ContactInfo { |
|||
// Block the thread for one second |
|||
// to simulate a service call |
|||
Thread.sleep(1000) |
|||
return ContactInfo("False Street 123", 11111) |
|||
} |
|||
|
|||
private fun createProfile(userInfo: UserInfo, contactInfo: ContactInfo): Profile { |
|||
return Profile(userInfo, contactInfo) |
|||
} |
|||
} |
|||
|
|||
// Concurrent implementation using suspending functions and |
|||
// asynchronous code |
|||
class Concurrent { |
|||
suspend fun getProfile(id: Int): Profile { |
|||
val basicUserInfo = asyncGetUserInfo(id) |
|||
val contactInfo = asyncGetContactInfo(id) |
|||
|
|||
return createProfile(basicUserInfo.await(), contactInfo.await()) |
|||
} |
|||
|
|||
private fun asyncGetUserInfo(id: Int) = async { |
|||
// Block the thread for one second |
|||
// to simulate a service call |
|||
Thread.sleep(1000) |
|||
|
|||
UserInfo("Susan", "Calvin") |
|||
} |
|||
|
|||
private fun asyncGetContactInfo(id: Int) = async { |
|||
// Block the thread for one second |
|||
// to simulate a service call |
|||
Thread.sleep(1000) |
|||
ContactInfo("False Street 123", 11111) |
|||
} |
|||
|
|||
private fun createProfile(userInfo: UserInfo, contactInfo: ContactInfo): Profile { |
|||
return Profile(userInfo, contactInfo) |
|||
} |
|||
} |
|||
|
|||
// Measuring their execution |
|||
fun main(args: Array<String>) { |
|||
val sequentialTime = measureTimeMillis { |
|||
val sequential = Sequential() |
|||
sequential.getProfile(1) |
|||
} |
|||
|
|||
val concurrentTime = measureTimeMillis { |
|||
runBlocking { |
|||
val concurrent = Concurrent() |
|||
concurrent.getProfile(1) |
|||
} |
|||
} |
|||
|
|||
println("Sequential took $sequentialTime ms") |
|||
println("Concurrent took $concurrentTime ms") |
|||
} |
@ -0,0 +1,18 @@ |
|||
package chapter1.section3 |
|||
|
|||
val words = listOf("level", "pope", "needle", "Anna", "Pete", "noon", "stats") |
|||
|
|||
fun main(args: Array<String>) { |
|||
filterPalindromes(words).forEach { |
|||
println(it) |
|||
} |
|||
} |
|||
|
|||
fun filterPalindromes(words: List<String>) : List<String> { |
|||
return words.filter { isPalindrome(it) } |
|||
} |
|||
|
|||
fun isPalindrome(word: String) : Boolean { |
|||
val lcWord = word.toLowerCase() |
|||
return lcWord == lcWord.reversed() |
|||
} |
@ -0,0 +1,23 @@ |
|||
package chapter1.section4 |
|||
|
|||
import kotlinx.coroutines.experimental.async |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
// This method will print values lower than 2100 often |
|||
fun main(args: Array<String>) = runBlocking { |
|||
val workerA = asyncIncrement(2000) |
|||
val workerB = asyncIncrement(100) |
|||
|
|||
workerA.await() |
|||
workerB.await() |
|||
|
|||
print("counter [$counter]") |
|||
} |
|||
|
|||
var counter = 0 |
|||
|
|||
fun asyncIncrement(by: Int) = async { |
|||
for (i in 0 until by) { |
|||
counter++ |
|||
} |
|||
} |
@ -0,0 +1,26 @@ |
|||
package chapter1.section4 |
|||
|
|||
import kotlinx.coroutines.experimental.Job |
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.launch |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
lateinit var jobA : Job |
|||
lateinit var jobB : Job |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
jobA = launch { |
|||
delay(1000) |
|||
// wait for JobB to finish |
|||
jobB.join() |
|||
} |
|||
|
|||
jobB = launch { |
|||
// wait for JobA to finish |
|||
jobA.join() |
|||
} |
|||
|
|||
// wait for JobA to finish |
|||
jobA.join() |
|||
println("Finished") |
|||
} |
@ -0,0 +1,22 @@ |
|||
package chapter1.section4 |
|||
|
|||
import kotlinx.coroutines.experimental.async |
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
data class UserInfo(val name: String, val lastName: String, val id: Int) |
|||
|
|||
lateinit var user: UserInfo |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
asyncGetUserInfo(1) |
|||
// Do some other operations |
|||
delay(1000) |
|||
|
|||
println("User ${user.id} is ${user.name}") |
|||
} |
|||
|
|||
fun asyncGetUserInfo(id: Int) = async { |
|||
delay(1100) |
|||
user = UserInfo(id = id, name = "Miguel", lastName = "Castiblanco") |
|||
} |
@ -0,0 +1,29 @@ |
|||
package chapter1.section5 |
|||
|
|||
import kotlinx.coroutines.experimental.async |
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
import kotlin.system.measureTimeMillis |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
val time = measureTimeMillis { |
|||
val name = async { getName() } |
|||
val lastName = async { getLastName() } |
|||
|
|||
println("Hello, ${name.await()} ${lastName.await()}") |
|||
} |
|||
|
|||
|
|||
|
|||
println("Execution took $time ms") |
|||
} |
|||
|
|||
suspend fun getName(): String { |
|||
delay(1000) |
|||
return "Susan" |
|||
} |
|||
|
|||
suspend fun getLastName(): String { |
|||
delay(1000) |
|||
return "Calvin" |
|||
} |
@ -0,0 +1,33 @@ |
|||
package chapter1.section5 |
|||
|
|||
import kotlinx.coroutines.experimental.async |
|||
|
|||
class Profile(userInfo: UserInfo, contactInfo: ContactInfo) |
|||
class UserInfo(name:String, lastName: String) |
|||
class ContactInfo(address: String, zipCode: Int) |
|||
|
|||
suspend fun getProfile(id: Int): Profile { |
|||
val basicUserInfo = asyncGetUserInfo(id) |
|||
val contactInfo = asyncGetContactInfo(id) |
|||
|
|||
return createProfile(basicUserInfo.await(), contactInfo.await()) |
|||
} |
|||
|
|||
private fun asyncGetUserInfo(id: Int) = async { |
|||
// Block the thread for one second |
|||
// to simulate a service call |
|||
Thread.sleep(1000) |
|||
|
|||
UserInfo("Susan", "Calvin") |
|||
} |
|||
|
|||
private fun asyncGetContactInfo(id: Int) = async { |
|||
// Block the thread for one second |
|||
// to simulate a service call |
|||
Thread.sleep(1000) |
|||
ContactInfo("False Street 123", 11111) |
|||
} |
|||
|
|||
private fun createProfile(userInfo: UserInfo, contactInfo: ContactInfo): Profile { |
|||
return Profile(userInfo, contactInfo) |
|||
} |
@ -0,0 +1,36 @@ |
|||
package chapter2.async |
|||
|
|||
import kotlinx.coroutines.experimental.async |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
val task = async { |
|||
doSomething() |
|||
} |
|||
|
|||
// This code will have the exception be propagated |
|||
task.await() |
|||
println("Completed") |
|||
|
|||
|
|||
/* This code will wait for the async to end and validate its output |
|||
task.join() |
|||
|
|||
if (task.isCompletedExceptionally) { |
|||
val exception = task.getCompletionExceptionOrNull()!! |
|||
println("Error with message: ${exception.message}") |
|||
} else { |
|||
println("Success") |
|||
}*/ |
|||
|
|||
/* This code will have the application end without any error |
|||
task.join() |
|||
|
|||
println("Completed") |
|||
*/ |
|||
|
|||
} |
|||
|
|||
fun doSomething() { |
|||
throw UnsupportedOperationException("Can't do") |
|||
} |
@ -0,0 +1,20 @@ |
|||
package chapter2.dispatcher |
|||
|
|||
import kotlinx.coroutines.experimental.launch |
|||
import kotlinx.coroutines.experimental.newSingleThreadContext |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
val netDispatcher = newSingleThreadContext(name = "ServiceCall") |
|||
|
|||
val task = launch(netDispatcher) { |
|||
printCurrentThread() |
|||
} |
|||
|
|||
task.join() |
|||
} |
|||
|
|||
fun printCurrentThread() { |
|||
println("Running in thread [${Thread.currentThread().name}]") |
|||
} |
|||
|
@ -0,0 +1,23 @@ |
|||
package chapter2.launch |
|||
|
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.launch |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
|
|||
val task = launch { |
|||
doSomething() |
|||
} |
|||
|
|||
task.join() |
|||
println("completed") |
|||
} |
|||
|
|||
suspend fun doSomething() { |
|||
delay(100) |
|||
println("Half-way to crash") |
|||
delay(100) |
|||
throw UnsupportedOperationException("Can't do") |
|||
|
|||
} |
@ -0,0 +1,31 @@ |
|||
package chapter3.deferred |
|||
|
|||
import kotlinx.coroutines.experimental.CompletableDeferred |
|||
import kotlinx.coroutines.experimental.async |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
/** |
|||
* Examples of how to instantiate a Deferred |
|||
*/ |
|||
fun main(args: Array<String>) = runBlocking { |
|||
// Create a Deferred using `async` |
|||
val headlines = async { |
|||
getHeadlines() |
|||
} |
|||
|
|||
// Wait for it to complete |
|||
headlines.await() |
|||
|
|||
// Create a Deferred using the factory function |
|||
val deferred = CompletableDeferred<Unit>() |
|||
} |
|||
|
|||
fun getHeadlines() { |
|||
// Nothing to do here |
|||
} |
|||
|
|||
// Dummy class |
|||
class Article |
|||
|
|||
// A deferred can be created using the constructor as well |
|||
val articles = CompletableDeferred<List<Article>>() |
@ -0,0 +1,20 @@ |
|||
package chapter3.deferred.exception |
|||
|
|||
import kotlinx.coroutines.experimental.async |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
/** |
|||
* An example having an exception propagate because |
|||
* we are listening to the Deferred using await(). |
|||
* Please notice that the last line will never be executed. |
|||
*/ |
|||
fun main(args: Array<String>) = runBlocking { |
|||
val deferred = async { |
|||
throw Exception("Not ready!") |
|||
} |
|||
|
|||
// Let it fail |
|||
deferred.await() |
|||
// The print will never happen |
|||
println(deferred.isCompletedExceptionally) |
|||
} |
@ -0,0 +1,20 @@ |
|||
package chapter3.deferred.exception |
|||
|
|||
import kotlinx.coroutines.experimental.async |
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
/** |
|||
* An example of how to wrap an exception |
|||
* inside a Deferred |
|||
*/ |
|||
fun main(args: Array<String>) = runBlocking { |
|||
val deferred = async { |
|||
throw Exception("Not ready!") |
|||
} |
|||
|
|||
// Wait for it to fail |
|||
delay(200) |
|||
println(deferred.isCompletedExceptionally) |
|||
|
|||
} |
@ -0,0 +1,28 @@ |
|||
package chapter3.finalstate |
|||
|
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.launch |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
import kotlin.system.measureTimeMillis |
|||
|
|||
/** |
|||
* This code tries to restart a Job by calling start() once |
|||
* it has reached a final state. Notice that calling start() |
|||
* has no effect since the state of a Job can only move forward |
|||
*/ |
|||
fun main(args: Array<String>) = runBlocking { |
|||
val time = measureTimeMillis { |
|||
val job = launch { |
|||
delay(2000) |
|||
} |
|||
|
|||
// Wait for it to complete once |
|||
job.join() |
|||
|
|||
// Restart the Job |
|||
job.start() |
|||
job.join() |
|||
} |
|||
|
|||
println("Took $time ms") |
|||
} |
@ -0,0 +1,19 @@ |
|||
package chapter3.job.cancellation |
|||
|
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.launch |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
/** |
|||
* This code cancels a Job without a cause |
|||
*/ |
|||
fun main(args: Array<String>) = runBlocking { |
|||
val job = launch { |
|||
// Do some work here |
|||
delay(5000) |
|||
} |
|||
|
|||
// timeout for the operation |
|||
delay(2000) |
|||
job.cancel() |
|||
} |
@ -0,0 +1,20 @@ |
|||
package chapter3.job.cancellation.withcause |
|||
|
|||
import kotlinx.coroutines.experimental.* |
|||
|
|||
/** |
|||
* This passes a cause when cancelling a Job |
|||
*/ |
|||
fun main(args: Array<String>) = runBlocking { |
|||
val job = launch { |
|||
// Do some work here |
|||
delay(5000) |
|||
} |
|||
|
|||
// timeout for the operation |
|||
delay(2000) |
|||
|
|||
// cause of the cancellation |
|||
val cause = Exception("Timeout!") |
|||
job.cancel(cause) |
|||
} |
@ -0,0 +1,18 @@ |
|||
package chapter3.job |
|||
|
|||
import kotlinx.coroutines.experimental.* |
|||
|
|||
/** |
|||
* This code instantiates a Job by using launch |
|||
* and another by using the factory function. Notice |
|||
* that in both cases they will be started automatically |
|||
*/ |
|||
fun main(args: Array<String>) = runBlocking { |
|||
val job = launch { |
|||
TODO("Not implemented yet!") |
|||
} |
|||
|
|||
val job2 = Job() |
|||
|
|||
delay(500) |
|||
} |
@ -0,0 +1,17 @@ |
|||
package chapter3.job.lazy.join |
|||
|
|||
import kotlinx.coroutines.experimental.CoroutineStart |
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.launch |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
/** |
|||
* This code start a Job lazily, and waits for its execution to complete |
|||
*/ |
|||
fun main(args: Array<String>) = runBlocking { |
|||
val job = launch(start = CoroutineStart.LAZY) { |
|||
delay(3000) |
|||
} |
|||
|
|||
job.join() |
|||
} |
@ -0,0 +1,16 @@ |
|||
package chapter3.job.lazy |
|||
|
|||
import kotlinx.coroutines.experimental.* |
|||
|
|||
/** |
|||
* This code creates a Job that will not be started |
|||
* automatically. Notice that since the Job is never |
|||
* actually started, the exception is not propagated |
|||
*/ |
|||
fun main(args: Array<String>) = runBlocking { |
|||
launch(start = CoroutineStart.LAZY) { |
|||
TODO("Not implemented yet!") |
|||
} |
|||
|
|||
delay(500) |
|||
} |
@ -0,0 +1,17 @@ |
|||
package chapter3.job.lazy.start |
|||
|
|||
import kotlinx.coroutines.experimental.CoroutineStart |
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.launch |
|||
|
|||
/** |
|||
* This code start a coroutine lazily but doesn't wait |
|||
* for it to complete |
|||
*/ |
|||
fun main(args: Array<String>) { |
|||
val job = launch(start = CoroutineStart.LAZY) { |
|||
delay(3000) |
|||
} |
|||
|
|||
job.start() |
|||
} |
@ -0,0 +1,29 @@ |
|||
package chapter4.client.deferred |
|||
|
|||
import kotlinx.coroutines.experimental.Deferred |
|||
import kotlinx.coroutines.experimental.async |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
val client : ProfileServiceRepository = ProfileServiceClient() |
|||
|
|||
val profile = client.asyncFetchById(12).await() |
|||
println(profile) |
|||
} |
|||
|
|||
data class Profile(val id: Long, val name: String, val age: Int) |
|||
|
|||
interface ProfileServiceRepository { |
|||
fun asyncFetchByName(name: String) : Deferred<Profile> |
|||
fun asyncFetchById(id: Long) : Deferred<Profile> |
|||
} |
|||
|
|||
class ProfileServiceClient : ProfileServiceRepository { |
|||
override fun asyncFetchByName(name: String) = async { |
|||
Profile(1, name, 28) |
|||
} |
|||
|
|||
override fun asyncFetchById(id: Long) = async { |
|||
Profile(id, "Susan", 28) |
|||
} |
|||
} |
@ -0,0 +1,28 @@ |
|||
package chapter4.client.suspending |
|||
|
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
val repository: ProfileServiceRepository = ProfileServiceClient() |
|||
|
|||
val profile = repository.fetchById(12) |
|||
println(profile) |
|||
} |
|||
|
|||
data class Profile(val id: Long, val name: String, val age: Int) |
|||
|
|||
interface ProfileServiceRepository { |
|||
suspend fun fetchByName(name: String) : Profile |
|||
suspend fun fetchById(id: Long) : Profile |
|||
} |
|||
|
|||
class ProfileServiceClient : ProfileServiceRepository { |
|||
override suspend fun fetchByName(name: String) : Profile { |
|||
return Profile(1, name, 28) |
|||
} |
|||
|
|||
override suspend fun fetchById(id: Long) : Profile { |
|||
return Profile(id, "Susan", 28) |
|||
} |
|||
|
|||
} |
@ -0,0 +1,59 @@ |
|||
package chapter4.context.dispatcher |
|||
|
|||
import kotlinx.coroutines.experimental.* |
|||
|
|||
/** |
|||
* This file contains examples of different types of dispatchers |
|||
*/ |
|||
|
|||
fun main(args: Array<String>) { |
|||
commonPool() |
|||
defaultDispatcher() |
|||
unconfined() |
|||
singleThread() |
|||
threadPool() |
|||
} |
|||
|
|||
fun commonPool() = runBlocking { |
|||
launch(CommonPool) { |
|||
println("Running in ${Thread.currentThread().name}") |
|||
}.join() |
|||
} |
|||
|
|||
fun defaultDispatcher() = runBlocking { |
|||
launch { |
|||
println("Running in ${Thread.currentThread().name}") |
|||
}.join() |
|||
|
|||
launch(DefaultDispatcher) { |
|||
println("Running in ${Thread.currentThread().name}") |
|||
}.join() |
|||
} |
|||
|
|||
fun unconfined() = runBlocking { |
|||
launch(Unconfined) { |
|||
println("Starting in ${Thread.currentThread().name}") |
|||
delay(500) |
|||
println("Resuming in ${Thread.currentThread().name}") |
|||
}.join() |
|||
} |
|||
|
|||
fun singleThread() = runBlocking { |
|||
val dispatcher = newSingleThreadContext("myThread") |
|||
|
|||
launch(dispatcher) { |
|||
println("Starting in ${Thread.currentThread().name}") |
|||
delay(500) |
|||
println("Resuming in ${Thread.currentThread().name}") |
|||
}.join() |
|||
} |
|||
|
|||
fun threadPool() = runBlocking { |
|||
val dispatcher = newFixedThreadPoolContext(4, "myPool") |
|||
|
|||
launch(dispatcher) { |
|||
println("Starting in ${Thread.currentThread().name}") |
|||
delay(500) |
|||
println("Resuming in ${Thread.currentThread().name}") |
|||
}.join() |
|||
} |
@ -0,0 +1,20 @@ |
|||
package chapter4.context.exception |
|||
|
|||
import kotlinx.coroutines.experimental.CoroutineExceptionHandler |
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.launch |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
val handler = CoroutineExceptionHandler({ context, throwable -> |
|||
println("Error captured in $context") |
|||
println("Message: ${throwable.message}") |
|||
}) |
|||
|
|||
launch(handler) { |
|||
TODO("Not implemented yet!") |
|||
} |
|||
|
|||
// wait for the error to happen |
|||
delay(500) |
|||
} |
@ -0,0 +1,22 @@ |
|||
package chapter4.context.mix.join |
|||
|
|||
import kotlinx.coroutines.experimental.CoroutineExceptionHandler |
|||
import kotlinx.coroutines.experimental.launch |
|||
import kotlinx.coroutines.experimental.newSingleThreadContext |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
val dispatcher = newSingleThreadContext("myDispatcher") |
|||
val handler = CoroutineExceptionHandler({ _, throwable -> |
|||
println("Error captured") |
|||
println("Message: ${throwable.message}") |
|||
}) |
|||
|
|||
// Combine two contexts together |
|||
val context = dispatcher + handler |
|||
|
|||
launch(context) { |
|||
println("Running in ${Thread.currentThread().name}") |
|||
TODO("Not implemented!") |
|||
}.join() |
|||
} |
@ -0,0 +1,25 @@ |
|||
package chapter4.context.mix.separate |
|||
|
|||
import kotlinx.coroutines.experimental.CoroutineExceptionHandler |
|||
import kotlinx.coroutines.experimental.launch |
|||
import kotlinx.coroutines.experimental.newSingleThreadContext |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
val dispatcher = newSingleThreadContext("myDispatcher") |
|||
val handler = CoroutineExceptionHandler({ _, throwable -> |
|||
println("Error captured") |
|||
println("Message: ${throwable.message}") |
|||
}) |
|||
|
|||
// Combine two contexts together |
|||
val context = dispatcher + handler |
|||
|
|||
// Remove one element from the context |
|||
val tmpCtx = context.minusKey(dispatcher.key) |
|||
|
|||
launch(tmpCtx) { |
|||
println("Running in ${Thread.currentThread().name}") |
|||
TODO("Not implemented!") |
|||
}.join() |
|||
} |
@ -0,0 +1,76 @@ |
|||
package chapter4.context.noncancellable |
|||
|
|||
import kotlinx.coroutines.experimental.* |
|||
import kotlin.system.measureTimeMillis |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
//cancellation() |
|||
//cancellationDelay() |
|||
nonCancellable() |
|||
} |
|||
|
|||
suspend fun cancellation() { |
|||
val duration = measureTimeMillis { |
|||
val job = launch { |
|||
try { |
|||
while (isActive) { |
|||
delay(500) |
|||
println("still running") |
|||
} |
|||
} finally { |
|||
println("cancelled, will end now") |
|||
} |
|||
} |
|||
|
|||
delay(1200) |
|||
job.cancelAndJoin() |
|||
} |
|||
|
|||
println("Took $duration ms") |
|||
} |
|||
|
|||
suspend fun cancellationDelay() { |
|||
val duration = measureTimeMillis { |
|||
val job = launch { |
|||
try { |
|||
while (isActive) { |
|||
delay(500) |
|||
println("still running") |
|||
} |
|||
} finally { |
|||
println("cancelled, will delay finalization now") |
|||
delay(5000) |
|||
println("delay completed, bye bye") |
|||
} |
|||
} |
|||
|
|||
delay(1200) |
|||
job.cancelAndJoin() |
|||
} |
|||
|
|||
println("Took $duration ms") |
|||
} |
|||
|
|||
suspend fun nonCancellable() { |
|||
val duration = measureTimeMillis { |
|||
val job = launch { |
|||
try { |
|||
while (isActive) { |
|||
delay(500) |
|||
println("still running") |
|||
} |
|||
} finally { |
|||
withContext(NonCancellable) { |
|||
println("cancelled, will delay finalization now") |
|||
delay(5000) |
|||
println("delay completed, bye bye") |
|||
} |
|||
} |
|||
} |
|||
|
|||
delay(1200) |
|||
job.cancelAndJoin() |
|||
} |
|||
|
|||
println("Took $duration ms") |
|||
} |
@ -0,0 +1,28 @@ |
|||
package chapter4.context.switch |
|||
|
|||
import kotlinx.coroutines.experimental.* |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
before() |
|||
after() |
|||
} |
|||
|
|||
suspend fun before() { |
|||
val dispatcher = newSingleThreadContext("myThread") |
|||
val name = async(dispatcher) { |
|||
// Do important operation here |
|||
"Susan Calvin" |
|||
}.await() |
|||
|
|||
println("User: $name") |
|||
} |
|||
|
|||
suspend fun after() { |
|||
val dispatcher = newSingleThreadContext("myThread") |
|||
val name = withContext(dispatcher) { |
|||
// Do important operation here |
|||
"Susan Calvin" |
|||
} |
|||
|
|||
println("User: $name") |
|||
} |
@ -0,0 +1,15 @@ |
|||
package chapter4.suspending |
|||
|
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
fun main(args: Array<String>) { |
|||
runBlocking { |
|||
greetDelayed(1000) |
|||
} |
|||
} |
|||
|
|||
suspend fun greetDelayed(delayMillis: Int) { |
|||
delay(delayMillis) |
|||
println("Hello, World!") |
|||
} |
@ -0,0 +1,103 @@ |
|||
package chapter5.iterator |
|||
|
|||
import kotlin.coroutines.experimental.buildIterator |
|||
|
|||
fun main(args: Array<String>) { |
|||
yieldValues() |
|||
buildingIterators() |
|||
allElements() |
|||
gettingNextValue() |
|||
validatingForElements() |
|||
notSuchElementException() |
|||
yieldingNote() |
|||
} |
|||
|
|||
fun yieldValues() { |
|||
val iterator = buildIterator { |
|||
yield("First") |
|||
yield("Second") |
|||
yield("Third") |
|||
} |
|||
|
|||
println(iterator.next()) |
|||
println(iterator.next()) |
|||
println(iterator.next()) |
|||
} |
|||
|
|||
fun buildingIterators() { |
|||
val iterator = buildIterator { |
|||
yield(1) |
|||
} |
|||
|
|||
val iterator2 : Iterator<Any> = buildIterator { |
|||
yield(1) |
|||
yield(10L) |
|||
yield("Hello") |
|||
} |
|||
} |
|||
|
|||
fun allElements() { |
|||
val iterator = buildIterator { |
|||
yield("First") |
|||
yield("Second") |
|||
yield("Third") |
|||
} |
|||
|
|||
iterator.forEach { |
|||
println(it) |
|||
} |
|||
} |
|||
|
|||
fun gettingNextValue() { |
|||
val iterator : Iterator<Any> = buildIterator { |
|||
yield(1) |
|||
yield(10L) |
|||
yield("Hello") |
|||
} |
|||
|
|||
println(iterator.next()) |
|||
println(iterator.next()) |
|||
println(iterator.next()) |
|||
} |
|||
|
|||
fun validatingForElements() { |
|||
val iterator = buildIterator { |
|||
for (i in 0..4) { |
|||
yield(i * 4) |
|||
} |
|||
} |
|||
|
|||
for (i in 0..5) { |
|||
if (iterator.hasNext()) { |
|||
println("element $i is ${iterator.next()}") |
|||
} else { |
|||
println("No more elements") |
|||
} |
|||
} |
|||
} |
|||
|
|||
fun notSuchElementException() { |
|||
val iterator = buildIterator { |
|||
yield(1) |
|||
} |
|||
|
|||
println(iterator.next()) |
|||
// Uncomment this line to reproduce the error |
|||
//println(iterator.next()) |
|||
} |
|||
|
|||
fun yieldingNote() { |
|||
val iterator = buildIterator { |
|||
println("yielding 1") |
|||
yield(1) |
|||
println("yielding 2") |
|||
yield(2) |
|||
} |
|||
|
|||
iterator.next() |
|||
|
|||
if (iterator.hasNext()) { |
|||
println("iterator has next") |
|||
iterator.next() |
|||
} |
|||
} |
@ -0,0 +1,23 @@ |
|||
package chapter5.iterator.fibonacci |
|||
|
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
import kotlin.coroutines.experimental.buildIterator |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
val fibonacci = buildIterator { |
|||
yield(1L) |
|||
var current = 1L |
|||
var next = 1L |
|||
while (true) { |
|||
yield(next) |
|||
val tmpNext = current + next |
|||
current = next |
|||
next = tmpNext |
|||
} |
|||
} |
|||
|
|||
for (i in 0..91) { |
|||
println("$i is ${fibonacci.next()}") |
|||
} |
|||
} |
|||
|
@ -0,0 +1,101 @@ |
|||
package chapter5.producer |
|||
|
|||
import kotlinx.coroutines.experimental.channels.* |
|||
import kotlinx.coroutines.experimental.newSingleThreadContext |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
fun main(args: Array<String>)= runBlocking { |
|||
creation() |
|||
//sample() |
|||
} |
|||
|
|||
suspend fun creation() { |
|||
|
|||
// Simple producer |
|||
val simpleProducer = produce { |
|||
send(1) |
|||
} |
|||
println(simpleProducer.receive()) |
|||
|
|||
// Producer with a CoroutineContext |
|||
val context = newSingleThreadContext("myThread") |
|||
val producerWithContext = produce(context) { |
|||
for (i in 0..9) { |
|||
println("sending $i") |
|||
send(i) |
|||
} |
|||
} |
|||
|
|||
producerWithContext.take(12).consumeEach { |
|||
println(it) |
|||
} |
|||
|
|||
// Typed producer |
|||
val typedProducer : ReceiveChannel<Any> = produce(context) { |
|||
send(5) |
|||
send("a") |
|||
} |
|||
} |
|||
|
|||
suspend fun readingAllTheElements() { |
|||
val context = newSingleThreadContext("myThread") |
|||
|
|||
val producer = produce(context) { |
|||
for (i in 0..9) { |
|||
send(i) |
|||
} |
|||
} |
|||
|
|||
producer.consumeEach { |
|||
println(it) |
|||
} |
|||
} |
|||
|
|||
suspend fun singleElement() { |
|||
val producer = produce { |
|||
send(5) |
|||
send("a") |
|||
} |
|||
|
|||
println(producer.receive()) |
|||
println(producer.receive()) |
|||
} |
|||
|
|||
suspend fun groupOfElements() { |
|||
val producer = produce { |
|||
for (i in 0..9) { |
|||
send(i) |
|||
} |
|||
} |
|||
|
|||
producer.take(3).consumeEach { |
|||
println(it) |
|||
} |
|||
} |
|||
|
|||
suspend fun moreThanAvailable() { |
|||
val producer = produce { |
|||
for (i in 0..9) { |
|||
send(i) |
|||
} |
|||
} |
|||
|
|||
producer.take(12).consumeEach { |
|||
println(it) |
|||
} |
|||
} |
|||
|
|||
suspend fun moreThanAvailableException() { |
|||
val producer = produce { |
|||
for (i in 0..9) { |
|||
send(i) |
|||
} |
|||
} |
|||
|
|||
producer.take(12).consumeEach { |
|||
println(it) |
|||
} |
|||
|
|||
// This line below would produce an exception |
|||
// val element = producer.receive() |
|||
} |
@ -0,0 +1,31 @@ |
|||
package chapter5.producer.fibonacci |
|||
|
|||
import kotlinx.coroutines.experimental.channels.consumeEach |
|||
import kotlinx.coroutines.experimental.channels.produce |
|||
import kotlinx.coroutines.experimental.channels.take |
|||
import kotlinx.coroutines.experimental.newSingleThreadContext |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
|
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
val thread = newSingleThreadContext("myThread") |
|||
|
|||
val fibonacci = produce(thread) { |
|||
send(1L) |
|||
var current = 1L |
|||
var next = 1L |
|||
while (true) { |
|||
send(next) |
|||
val tmpNext = current + next |
|||
current = next |
|||
next = tmpNext |
|||
} |
|||
} |
|||
|
|||
fibonacci.take(10).consumeEach { |
|||
println(it) |
|||
} |
|||
|
|||
} |
|||
|
|||
|
@ -0,0 +1,82 @@ |
|||
package chapter5.sequence |
|||
|
|||
import kotlin.coroutines.experimental.buildSequence |
|||
|
|||
fun main(args: Array<String>) { |
|||
simpleSequences() |
|||
readingAllTheValues() |
|||
elementAt() |
|||
elementAtOrElse() |
|||
elementAtOrNull() |
|||
groupOfElements() |
|||
stateless() |
|||
} |
|||
|
|||
fun simpleSequences() { |
|||
val sequence = buildSequence { |
|||
yield(1) |
|||
} |
|||
|
|||
val sequence2 : Sequence<Any> = buildSequence { |
|||
yield("A") |
|||
yield(1) |
|||
yield(32L) |
|||
} |
|||
} |
|||
|
|||
val sequence = buildSequence { |
|||
yield(1) |
|||
yield(1) |
|||
yield(2) |
|||
yield(3) |
|||
yield(5) |
|||
yield(8) |
|||
yield(13) |
|||
yield(21) |
|||
} |
|||
|
|||
fun readingAllTheValues() { |
|||
sequence.forEach { |
|||
print("$it ") |
|||
} |
|||
|
|||
println() |
|||
sequence.forEachIndexed { index, value -> |
|||
println("element at $index is $value") |
|||
} |
|||
} |
|||
|
|||
fun elementAt() { |
|||
println(sequence.elementAt(4)) |
|||
} |
|||
|
|||
fun elementAtOrElse() { |
|||
println(sequence.elementAtOrElse(10, { it * 2 })) |
|||
} |
|||
|
|||
fun elementAtOrNull() { |
|||
println(sequence.elementAtOrNull(10)) |
|||
} |
|||
|
|||
fun groupOfElements() { |
|||
val firstFive = sequence.take(5) |
|||
println(firstFive.joinToString()) |
|||
} |
|||
|
|||
fun stateless() { |
|||
val sequence = buildSequence { |
|||
for (i in 0..9) { |
|||
println("Yielding $i") |
|||
yield(i) |
|||
} |
|||
} |
|||
|
|||
println("Requesting index 1") |
|||
sequence.elementAt(1) |
|||
|
|||
println("Requesting index 2") |
|||
sequence.elementAt(2) |
|||
|
|||
println("Taking 3") |
|||
sequence.take(3).joinToString() |
|||
} |
@ -0,0 +1,30 @@ |
|||
package chapter5.sequence.fibonacci |
|||
|
|||
import kotlin.coroutines.experimental.buildSequence |
|||
|
|||
fun main(args: Array<String>) { |
|||
|
|||
val fibonacci = buildSequence { |
|||
println("Yielding 1") |
|||
yield(1L) |
|||
var current = 1L |
|||
var next = 1L |
|||
while (true) { |
|||
println("Yielding $next") |
|||
yield(next) |
|||
val tmpNext = current + next |
|||
current = next |
|||
next = tmpNext |
|||
} |
|||
} |
|||
|
|||
println(fibonacci.elementAt(1)) |
|||
println(fibonacci.elementAt(2)) |
|||
val indexed = fibonacci.take(50).withIndex() |
|||
|
|||
for ((index, value) in indexed) { |
|||
println("$index: $value") |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,29 @@ |
|||
package chapter6.buffered.array |
|||
|
|||
import kotlinx.coroutines.experimental.channels.Channel |
|||
import kotlinx.coroutines.experimental.channels.take |
|||
import kotlinx.coroutines.experimental.delay |
|||
import kotlinx.coroutines.experimental.launch |
|||
import kotlinx.coroutines.experimental.runBlocking |
|||
import kotlin.system.measureTimeMillis |
|||
|
|||
fun main(args: Array<String>) = runBlocking { |
|||
val time = measureTimeMillis { |
|||
val channel = Channel<Int>(4) |
|||
val sender = launch(coroutineContext) { |
|||
repeat(10) { |
|||
println("Sending $it") |
|||
channel.send(it) |
|||
} |
|||
} |
|||
|
|||
delay(500) |
|||
println("Taking two") |
|||
channel.take(2).receive() |
|||
delay(500) |
|||
|
|||
sender.cancel() |
|||
} |
|||
|
|||
println("Took ${time}ms") |
|||
} |