Kotlin/Native samples ported to MPP Gradle DSL (#2261)
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
# Workers
|
||||
|
||||
This example shows how one could implement computation offload to other workers
|
||||
This example shows how one could implement computation offload to other workers
|
||||
(usually mapped to OS threads) and transfer data back and forth between workers.
|
||||
Idea of workers is to avoid most common problems with concurrent programming, related
|
||||
to simultaneous computations on the same data. Instead, each object belongs to
|
||||
one or other worker's object graph, but could be disconnected from one worker
|
||||
and connected to other worker. This relies on fact that memory management
|
||||
and connected to other worker. This relies on the fact that memory management
|
||||
engine can ensure, that one worker doesn't keep references to certain object and
|
||||
whatever it refers to, and so the object could be safely transferred to another worker.
|
||||
|
||||
@@ -15,11 +15,13 @@ between workers, as long, as they do not refer to objects, having external refer
|
||||
|
||||
The transfer is implemented with the function `execute()` having the following signature
|
||||
|
||||
fun <T1, T2> execute(mode: TransferMode,
|
||||
producer: () -> T1,
|
||||
@VolatileLambda job: (T1) -> T2): Future<T2>
|
||||
fun <T1, T2> execute(
|
||||
mode: TransferMode,
|
||||
producer: () -> T1,
|
||||
@VolatileLambda job: (T1) -> T2
|
||||
): Future<T2>
|
||||
|
||||
Kotlin/Native runtime invokes `producer()` function, and makes sure object it produces
|
||||
Kotlin/Native runtime invokes `producer()` function, and makes sure object it produces
|
||||
have a property, that no external references to subgraph rooted by this object, exists.
|
||||
If property doesn't hold, either (depending on `mode` argument) exception is being thrown
|
||||
or program may crash unexpectedly.
|
||||
@@ -29,11 +31,13 @@ is being created. Once worker peeks the job from the queue, it executes stateles
|
||||
with object provided, and stores stable pointer to result in future's data. Whenever
|
||||
future is being consumed, object is passed to the consumer's callback.
|
||||
|
||||
This particular example starts several workers, and gives them some computational jobs.
|
||||
This particular example starts several workers, and gives them some computational jobs.
|
||||
Then it continues execution, and waits on future objects encapsulating the
|
||||
computation results. Afterwards, worker execution termination is requested with the
|
||||
`requestTermination()` operation.
|
||||
|
||||
To build use `./build.sh` or `./gradlew assemble`
|
||||
To build use `../gradlew assemble`.
|
||||
|
||||
To run use `./build/exe/main/release/workers.kexe`
|
||||
To run use `../gradlew runProgram` or execute the program directly:
|
||||
|
||||
./build/bin/workers/main/release/executable/workers.kexe
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
apply plugin: 'org.jetbrains.kotlin.platform.native'
|
||||
plugins {
|
||||
id 'kotlin-multiplatform'
|
||||
}
|
||||
|
||||
components.main {
|
||||
outputKinds = [ EXECUTABLE ]
|
||||
}
|
||||
kotlin {
|
||||
targets {
|
||||
fromPreset(MPPTools.defaultHostPreset(project), 'workers') {
|
||||
compilations.main.outputKinds 'EXECUTABLE'
|
||||
compilations.main.entryPoint 'sample.workers.main'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MPPTools.createRunTask(project, 'runProgram', kotlin.targets.workers)
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
DIR=$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
source "$DIR/../konan.sh"
|
||||
|
||||
SUFFIX=kexe
|
||||
if [ x$TARGET == x ]; then
|
||||
case "$OSTYPE" in
|
||||
darwin*) TARGET=macbook ;;
|
||||
linux*) TARGET=linux ;;
|
||||
msys*) TARGET=mingw; SUFFIX=exe ;;
|
||||
*) echo "unknown: $OSTYPE" && exit 1;;
|
||||
esac
|
||||
fi
|
||||
|
||||
var=CFLAGS_${TARGET}
|
||||
CFLAGS=${!var}
|
||||
var=LINKER_ARGS_${TARGET}
|
||||
LINKER_ARGS=${!var}
|
||||
var=COMPILER_ARGS_${TARGET}
|
||||
COMPILER_ARGS=${!var} # add -opt for an optimized build.
|
||||
|
||||
mkdir -p $DIR/build/bin/
|
||||
|
||||
konanc $COMPILER_ARGS -target $TARGET $DIR/src/main/kotlin/Workers.kt \
|
||||
-o $DIR/build/bin/Workers || exit 1
|
||||
|
||||
echo "Artifact could be found at $DIR/build/bin/Workers.$SUFFIX"
|
||||
@@ -0,0 +1,2 @@
|
||||
kotlin.code.style=official
|
||||
kotlin.import.noCommonSourceSets=true
|
||||
+16
-7
@@ -1,22 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package sample.workers
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
data class WorkerArgument(val intParam: Int, val stringParam: String)
|
||||
data class WorkerResult(val intResult: Int, val stringResult: String)
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
fun main() {
|
||||
val COUNT = 5
|
||||
val workers = Array(COUNT, { _ -> Worker.start()})
|
||||
val workers = Array(COUNT, { _ -> Worker.start() })
|
||||
|
||||
for (attempt in 1 .. 3) {
|
||||
val futures = Array(workers.size, { workerIndex -> workers[workerIndex].execute(TransferMode.SAFE, {
|
||||
WorkerArgument(workerIndex, "attempt $attempt") }) { input ->
|
||||
for (attempt in 1..3) {
|
||||
val futures = Array(workers.size) { workerIndex ->
|
||||
workers[workerIndex].execute(TransferMode.SAFE, {
|
||||
WorkerArgument(workerIndex, "attempt $attempt")
|
||||
}) { input ->
|
||||
var sum = 0
|
||||
for (i in 0..input.intParam * 1000) {
|
||||
sum += i
|
||||
}
|
||||
WorkerResult(sum, input.stringParam + " result")
|
||||
}
|
||||
})
|
||||
}
|
||||
val futureSet = futures.toSet()
|
||||
var consumed = 0
|
||||
while (consumed < futureSet.size) {
|
||||
@@ -32,5 +41,5 @@ fun main(args: Array<String>) {
|
||||
workers.forEach {
|
||||
it.requestTermination().result
|
||||
}
|
||||
println("OK")
|
||||
println("Workers: OK")
|
||||
}
|
||||
Reference in New Issue
Block a user