Move everything under kotlin-native folder
I was forced to manually do update the following files, because otherwise they would be ignored according .gitignore settings. Probably they should be deleted from repo. Interop/.idea/compiler.xml Interop/.idea/gradle.xml Interop/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_runtime_1_0_3.xml Interop/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_0_3.xml Interop/.idea/modules.xml Interop/.idea/modules/Indexer/Indexer.iml Interop/.idea/modules/Runtime/Runtime.iml Interop/.idea/modules/StubGenerator/StubGenerator.iml backend.native/backend.native.iml backend.native/bc.frontend/bc.frontend.iml backend.native/cli.bc/cli.bc.iml backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt backend.native/tests/link/lib/foo.kt backend.native/tests/link/lib/foo2.kt backend.native/tests/teamcity-test.property
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
# 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 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.
|
||||
|
||||
Workers do not share mutable state, but share executable code of the program and some
|
||||
immutable data, such as immutable 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 `execute()` having the following signature
|
||||
|
||||
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
|
||||
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 `../gradlew assemble`.
|
||||
|
||||
To run use `../gradlew runReleaseExecutableWorkers` or execute the program directly:
|
||||
|
||||
./build/bin/workers/main/release/executable/workers.kexe
|
||||
@@ -0,0 +1,24 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
// Determine host preset.
|
||||
val hostOs = System.getProperty("os.name")
|
||||
|
||||
// Create target for the host platform.
|
||||
val hostTarget = when {
|
||||
hostOs == "Mac OS X" -> macosX64("workers")
|
||||
hostOs == "Linux" -> linuxX64("workers")
|
||||
hostOs.startsWith("Windows") -> mingwX64("workers")
|
||||
else -> throw GradleException("Host OS '$hostOs' is not supported in Kotlin/Native $project.")
|
||||
}
|
||||
|
||||
hostTarget.apply {
|
||||
binaries {
|
||||
executable {
|
||||
entryPoint = "sample.workers.main"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
kotlin.code.style=official
|
||||
kotlin.import.noCommonSourceSets=true
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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() {
|
||||
val COUNT = 5
|
||||
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 ->
|
||||
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 = waitForMultipleFutures(futureSet, 10000)
|
||||
ready.forEach {
|
||||
it.consume { result ->
|
||||
if (result.stringResult != "attempt $attempt result") throw Error("Unexpected $result")
|
||||
consumed++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
workers.forEach {
|
||||
it.requestTermination().result
|
||||
}
|
||||
println("Workers: OK")
|
||||
}
|
||||
Reference in New Issue
Block a user