v0.3.1 preparations. (#806)
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
# 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
|
||||
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.
|
||||
|
||||
Workers do not share any state (i.e. globals and Kotlin static objects have different
|
||||
values in different workers), but share executable code of the program and some
|
||||
immutable data, such as immutable binary blobs. But Kotlin objects can be transferred
|
||||
between workers, as long, as they do not refer to objects, having external references.
|
||||
|
||||
The transfer is implemented with the function `schedule()` having the following signature
|
||||
|
||||
fun <T1, T2>
|
||||
schedule(mode: TransferMode,
|
||||
producer: () -> T1,
|
||||
@VolatileLambda job: (T1) -> T2): Future<T2>
|
||||
|
||||
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.
|
||||
Then, pointer to stateless lambda `job` along with the stable pointer to parameter object
|
||||
is being added to the target worker's queue, and `Future` object matching to the query
|
||||
is being created. Once worker peeks the job from the queue, it executes stateless lambda
|
||||
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.
|
||||
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`.
|
||||
|
||||
To run use `./build/konan/bin/Worker.kexe`
|
||||
@@ -0,0 +1,35 @@
|
||||
import konan.worker.*
|
||||
|
||||
data class WorkerArgument(val intParam: Int, val stringParam: String)
|
||||
data class WorkerResult(val intResult: Int, val stringResult: String)
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val COUNT = 5
|
||||
val workers = Array(COUNT, { _ -> startWorker()})
|
||||
|
||||
for (attempt in 1 .. 3) {
|
||||
val futures = Array(workers.size, { workerIndex -> workers[workerIndex].schedule(TransferMode.CHECKED, {
|
||||
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) {
|
||||
val ready = futureSet.waitForMultipleFutures(10000)
|
||||
ready.forEach {
|
||||
it.consume { result ->
|
||||
if (result.stringResult != "attempt $attempt result") throw Error("Unexpected $result")
|
||||
consumed++ }
|
||||
}
|
||||
}
|
||||
}
|
||||
workers.forEach {
|
||||
it.requestTermination().consume { _ -> }
|
||||
}
|
||||
println("OK")
|
||||
}
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
DIR=$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
PATH=$DIR/../../dist/bin:$DIR/../../bin:$PATH
|
||||
|
||||
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/Workers.kt \
|
||||
-o $DIR/build/bin/Workers || exit 1
|
||||
|
||||
echo "Artifact could be found at $DIR/build/bin/Workers.$SUFFIX"
|
||||
Reference in New Issue
Block a user