diff --git a/README.md b/README.md index 9351da8..49ebe1a 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ fun swapEnds(first, args..., last, f) { delay(1.5) // coroutine is delayed for 1.5s, thread is not blocked! ``` and it is multithreaded on platforms supporting it (automatically, no code changes required, just -`launch` more coroutines and they will be executed concurrently if possible)/ +`launch` more coroutines and they will be executed concurrently if possible). See [parallelism] - functional style and OOP together, multiple inheritance, implementing interfaces for existing classes, writing extensions. - Any unicode letters can be used as identifiers: `assert( sin(π/2) == 1 )`. @@ -142,12 +142,12 @@ Ready features: Under way: -- [ ] maps, sets and sequences (flows?) +- [x] maps, sets and sequences (flows?) - [ ] regular exceptions -- [ ] modules -- [ ] string interpolation and more string tools +- [x] modules +- [x] string formatting and tools - [ ] multiple inheritance for user classes -- [ ] launch, deferred, coroutineScope, mutex, etc. +- [x] launch, deferred, CompletableDeferred, Mutex, etc. - [ ] site with integrated interpreter to give a try - [ ] kotlin part public API good docs, integration focused - [ ] better stack reporting @@ -158,10 +158,12 @@ Planned features. - [ ] type specifications - [ ] source docs and maybe lyng.md to a standard -- [ ] moacro-style kotlin integration or something else to simplify it +- [ ] macro-style kotlin integration or something else to simplify it Further - [ ] client with GUI support based on compose multiplatform somehow - [ ] notebook - style workbooks with graphs, formulaes, etc. -- [ ] language server or compose-based lyng-aware editor \ No newline at end of file +- [ ] language server or compose-based lyng-aware editor + +[parallelism]: docs/parallelism.md \ No newline at end of file diff --git a/docs/parallelism.md b/docs/parallelism.md index 13ca5de..baf5cb1 100644 --- a/docs/parallelism.md +++ b/docs/parallelism.md @@ -98,7 +98,6 @@ Sometimes it is convenient to manually set completion status of some deferred re // and as any other deferred it is now complete: assert(done.isCompleted) - ## True parallelism Cooperative, coroutine-based parallelism is automatically available on all platforms. Depending on the platform, though, the coroutines could be dispatched also in different threads; where there are multiple cores and/or CPU available, it means the coroutines could be exuted truly in parallel, unless [Mutex] is used: @@ -116,3 +115,16 @@ Cooperative, coroutine-based parallelism is automatically available on all platf So it is important to always use [Mutex] where concurrent execution could be a problem (so called Race Conditions, or RC). +## Yield + +When the coroutine is executed, on the single-threaded environment all other coroutines are suspended until active one will wait for something. Sometimes, it is undesirable; the coroutine may perform long calculations or some other CPU consuming task. The solution is to call `yield()` periodically. Unlike `delay()`, yield does not pauses the coroutine for some specified time, but it just makes all other coroutines to be executed. In other word, yield interrupts current coroutines and out it to the end of the dispatcher list of active coroutines. It is especially important on Javascript and wasmJS targets as otherwise UI thread could be blocked. + +Usage example: + + fun someLongTask() { // ... + do { + // execute step + if( done ) break + yield() + } while(true) + } diff --git a/docs/tutorial.md b/docs/tutorial.md index 8af8a28..438d69b 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -14,6 +14,7 @@ __Other documents to read__ maybe after this one: - [Advanced topics](advanced_topics.md), [declaring arguments](declaring_arguments.md) - [OOP notes](OOP.md), [exception handling](exceptions_handling.md) - [math in Lyng](math.md) +- [parallelism] - multithreaded code, coroutines, etc. - Some class references: [List], [Set], [Map], [Real], [Range], [Iterable], [Iterator], [time manipulation](time.md) - Some samples: [combinatorics](samples/combinatorics.lyng.md), national vars and loops: [сумма ряда](samples/сумма_ряда.lyng.md). More at [samples folder](samples) @@ -1278,4 +1279,5 @@ See [math functions](math.md). Other general purpose functions are: [string formatting]: https://github.com/sergeych/mp_stools?tab=readme-ov-file#sprintf-syntax-summary [Set]: Set.md [Map]: Map.md -[Buffer]: Buffer.md \ No newline at end of file +[Buffer]: Buffer.md +[parallelism]: parallelism.md \ No newline at end of file diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Script.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Script.kt index f285ce0..2888b7c 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Script.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/Script.kt @@ -1,6 +1,7 @@ package net.sergeych.lyng import kotlinx.coroutines.delay +import kotlinx.coroutines.yield import net.sergeych.lyng.obj.* import net.sergeych.lyng.pacman.ImportManager import net.sergeych.lynon.ObjLynonClass @@ -187,6 +188,11 @@ class Script( }) } + addFn("yield") { + yield() + ObjVoid + } + val pi = ObjReal(PI) addConst("π", pi) diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDeferred.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDeferred.kt index ec2f870..437cd96 100644 --- a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDeferred.kt +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjDeferred.kt @@ -1,10 +1,7 @@ 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() { @@ -33,19 +30,3 @@ open class ObjDeferred(val deferred: Deferred): Obj() { } } -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(0) - thisAs().mutex.withLock { f.execute(this) } - } - } - } -} \ No newline at end of file diff --git a/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMutex.kt b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMutex.kt new file mode 100644 index 0000000..b74675b --- /dev/null +++ b/lynglib/src/commonMain/kotlin/net/sergeych/lyng/obj/ObjMutex.kt @@ -0,0 +1,23 @@ +package net.sergeych.lyng.obj + +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import net.sergeych.lyng.Scope +import net.sergeych.lyng.Statement + +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(0) + thisAs().mutex.withLock { f.execute(this) } + } + } + } +} \ No newline at end of file