fix #47 parallelism: launch, Deferred, CompletableDeferred, Mutex (delay was already implemented)
This commit is contained in:
1 parent
de71c7c8ec
commit
19f8b6605b
9 files changed
+280
-2
No files matched your search
@@ -48,7 +48,6 @@ data class Arguments(val list: List<Obj>, val tailBlockMode: Boolean = false) :
|
||||
|
||||
fun inspect(): String = list.joinToString(", ") { it.inspect() }
|
||||
|
||||
|
||||
companion object {
|
||||
val EMPTY = Arguments(emptyList())
|
||||
fun from(values: Collection<Obj>) = Arguments(values.toList())
|
||||
|
||||
@@ -4,6 +4,7 @@ import kotlinx.coroutines.delay
|
||||
import net.sergeych.lyng.obj.*
|
||||
import net.sergeych.lyng.pacman.ImportManager
|
||||
import net.sergeych.lynon.ObjLynonClass
|
||||
import net.sergeych.mp_tools.globalDefer
|
||||
import kotlin.math.*
|
||||
|
||||
class Script(
|
||||
@@ -175,6 +176,18 @@ class Script(
|
||||
addConst("Array", ObjArray)
|
||||
addConst("Class", ObjClassType)
|
||||
|
||||
addConst("Deferred", ObjDeferred.type)
|
||||
addConst("CompletableDeferred", ObjCompletableDeferred.type)
|
||||
addConst("Mutex", ObjMutex.type)
|
||||
|
||||
addFn("launch") {
|
||||
val callable = args.firstAndOnly() as Statement
|
||||
ObjDeferred(globalDefer {
|
||||
callable.execute(this@addFn)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
val pi = ObjReal(PI)
|
||||
addConst("π", pi)
|
||||
getOrCreateNamespace("Math").apply {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import net.sergeych.lyng.Scope
|
||||
|
||||
class ObjCompletableDeferred(val completableDeferred: CompletableDeferred<Obj>): ObjDeferred(completableDeferred) {
|
||||
|
||||
override val objClass = type
|
||||
|
||||
companion object {
|
||||
val type = object: ObjClass("CompletableDeferred", ObjDeferred.type){
|
||||
override suspend fun callOn(scope: Scope): Obj {
|
||||
return ObjCompletableDeferred(CompletableDeferred())
|
||||
}
|
||||
}.apply {
|
||||
addFn("complete") {
|
||||
thisAs<ObjCompletableDeferred>().completableDeferred.complete(args.firstAndOnly())
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.Statement
|
||||
|
||||
open class ObjDeferred(val deferred: Deferred<Obj>): Obj() {
|
||||
|
||||
override val objClass = type
|
||||
|
||||
companion object {
|
||||
val type = object: ObjClass("Deferred"){
|
||||
override suspend fun callOn(scope: Scope): Obj {
|
||||
scope.raiseError("Deferred constructor is not directly callable")
|
||||
}
|
||||
}.apply {
|
||||
addFn("await") {
|
||||
thisAs<ObjDeferred>().deferred.await()
|
||||
}
|
||||
addFn("isCompleted") {
|
||||
thisAs<ObjDeferred>().deferred.isCompleted.toObj()
|
||||
}
|
||||
addFn("isActive") {
|
||||
thisAs<ObjDeferred>().deferred.isActive.toObj()
|
||||
}
|
||||
addFn("isCancelled") {
|
||||
thisAs<ObjDeferred>().deferred.isCancelled.toObj()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ObjMutex(val mutex: Mutex): Obj() {
|
||||
override val objClass = type
|
||||
|
||||
companion object {
|
||||
val type = object: ObjClass("Mutex") {
|
||||
override suspend fun callOn(scope: Scope): Obj {
|
||||
return ObjMutex(Mutex())
|
||||
}
|
||||
}.apply {
|
||||
addFn("withLock") {
|
||||
val f = requiredArg<Statement>(0)
|
||||
thisAs<ObjMutex>().mutex.withLock { f.execute(this) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import net.sergeych.lyng.eval
|
||||
import kotlin.test.Test
|
||||
|
||||
class TestCoroutines {
|
||||
|
||||
@Test
|
||||
fun testLaunch() = runTest {
|
||||
eval(
|
||||
"""
|
||||
var passed = false
|
||||
val x = launch {
|
||||
delay(10)
|
||||
passed = true
|
||||
"ok"
|
||||
}
|
||||
assert(!passed)
|
||||
assertEquals( x.await(), "ok")
|
||||
assert(passed)
|
||||
assert(x.isCompleted)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCompletableDeferred() = runTest {
|
||||
eval(
|
||||
"""
|
||||
val done = CompletableDeferred()
|
||||
|
||||
launch {
|
||||
delay(10)
|
||||
done.complete("ok")
|
||||
}
|
||||
|
||||
assert(!done.isCompleted)
|
||||
assert(done.isActive)
|
||||
assertEquals( done.await(), "ok")
|
||||
assert(done.isCompleted)
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMutex() = runTest {
|
||||
eval(
|
||||
"""
|
||||
var counter = 0
|
||||
val mutex = Mutex()
|
||||
|
||||
(1..4).map {
|
||||
launch {
|
||||
// mutex.withLock {
|
||||
val c = counter
|
||||
delay(5)
|
||||
counter = c + 1
|
||||
// }
|
||||
}
|
||||
}.forEach { it.await() }
|
||||
println(counter)
|
||||
assert( counter < 10 )
|
||||
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -299,4 +299,9 @@ class BookTest {
|
||||
runDocTests("../docs/time.md")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testParallelismBook() = runBlocking {
|
||||
runDocTests("../docs/parallelism.md")
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user