You can have multiple threads in Kotlin/Native. ~Each thread can have its own event loop with runBlocking and have number of coroutines running there~. Currently communication between those threads via coroutine primitives (like channels) is not supported. This issue it to track enhancement of Kotlin/Native in kotlinx.coroutines library so that all the following becomes possible:
UPDATE: Currently, coroutines are supported only on the main thread. You cannot have coroutines off the main thread due to the way the library is currently structured.
UPDATE 2: the separate library version that supports Kotlin/Native multithreading is released on a regular basis.
For the details and limitations, please follow kotlin-native-sharing.md document.
The latest version: 1.4.3-native-mt
Do you have a ballpark time frame for implementing this (days, weeks, months, ...)? This will help me plan how to implement the first revision of our project. Thanks!
Second that. Can we please get a rough estimate?
We're in the design phase now. I'll update you on the status in couple of weeks.
Have any progress?
We have a work-in-progress branch in this repo with some of the code that is implemented, but it is way too complex a change, so the work there was stopped. It is hard to get it done in the current state. We've refocused our efforts on delivering high-quality single-threaded coroutines which work really well for sharing logic between Android and iOS UI apps (I highly recommend to checkout the code of KotlinConf app here https://github.com/JetBrains/kotlinconf-app). With respect to multithreading, we'll be back to drawing board to see how this story can be made easier to code with. Don't expect results soon, though.
Does this mean it can already work without runBlocking, i.e. with launch?
Because that's really something I'd like to advantage of to make
multiplatform UI contracts.
On Thu, Oct 11, 2018, 11:03 PM Roman Elizarov notifications@github.com
wrote:
We have a work-in-progress branch in this repo with some of the code that
is implemented, but it is way too complex a change, so the work there was
stopped. It is hard to get it done in the current state. We've refocused
our efforts on delivering high-quality single-threaded coroutines which
work really well for sharing logic between Android and iOS UI apps (I
highly recommend to checkout the code of KotlinConf app here
https://github.com/JetBrains/kotlinconf-app). With respect to
multithreading, we'll be back to drawing board to see how this story can be
made easier to code with. Don't expect results soon, though.—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/Kotlin/kotlinx.coroutines/issues/462#issuecomment-429117616,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AGpvBbJNoE1CfiTsRyODDVV-FqOf-diVks5uj7ITgaJpZM4VjGFc
.
Yes, it works without runBlocking. The only extra effort you have to make, is you have to write a trivial UI CoroutineDispatcher for iOS. We don't include it in the library yet (that's issue #470), but you can copy-and-paste code from KotlinConf app (swift version here https://github.com/JetBrains/kotlinconf-app/blob/master/konfios/konfswift/ui/UI.swift) of from discussion in #470 (Kotlin version here https://github.com/Kotlin/kotlinx.coroutines/issues/470#issuecomment-414635811)
@elizarov Trying to convert Waiting for a job example to work without run blocking using (https://github.com/Kotlin/kotlinx.coroutines/issues/470#issuecomment-414635811) in a native macOs program. But I am still getting There is no event loop. Use runBlocking { ... } to start one. I think it probably is because my native program isn't starting NSRunLoop's mainloop. I can't quite figure it out.
I've tried starting the loop like:
fun main(args: Array<String>) {
val job = GlobalScope.launch(MainLoopDispatcher) { // launch new coroutine and keep a reference to its Job
delay(1000L)
println("World!")
}
println("Hello,")
NSRunLoop.currentRunLoop().runUntilDate(NSDate().dateByAddingTimeInterval(3.toDouble()))
}
But I don't think I'm doing that correctly, any ideas?
@luca992 please use runBlocking:
fun main(args: Array<String>) = runBlocking<Unit> { // <- This line
val job = GlobalScope.launch(MainLoopDispatcher) {
delay(1000L)
println("World!")
}
println("Hello,")
}
@qwwdfsad I know that it works with run blocking... Are you saying it is only possible to run without runBlocking on iOS for some reason?
Edit:
I'm using Qt for the UI in my native kotlin desktop app. Didn't figure out NSRunLoop. But, I figured out that if I run QGuiApplication.exec() inside runBlocking, I can call coroutines with Dispatchers.Unconfined. (And not have to wrap each one in runBlocking) .... Which is great beacuse now I can share presenters between the android app and the native desktop apps 👍
Is there any solution to support MultiThreaded coroutines yet?
As far as I know, under current Kotlin/Native threading model, if an object is going to be shared between workers/threads, it must be either frozen or use a DetachedObjectGraph, while none of which works with CouroutineDispatcher, because we have a Continuation to pass through. Sadly the Continuation captures coroutine context (maybe more othre objects), which makes it impossible to froze or detach a Continuation.
IMHO, It's nearly impossible to implement a multi-threading coroutine dispatcher under current Kotlin/Native threading model. Should we redesign the threading model?
Maybe it is good for writing rebust code that, Kotlin/Native implement Lock/Thread/ThreadPool, and use those tools to implement coroutine. For those just want to offload jobs to different thread, it is good enough to use coroutine. And for those who cares very much about performace, give them the ability to use raw thread/thread pool. For example, to write a high performance low latency audio app, one usually create threads with the hieghest scheduling proiorty, and event bind those threads to a certain cpu core to eliminate context switch.
Current my solution is to totally move the threading part into native ios code. like this.
private val requestingHashMap = hashMapOf<String, IosHttpGetAgent.Callback>()
fun notifyHttpGetResponse(url: String, result: String?, error: String) {
requestingHashMap.remove(url)?.onGetResult(url, result, error)
}
@Throws(IOException::class)
actual suspend fun httpGet(url: String): String {
return suspendCoroutine { continuation ->
val cb = object : IosHttpGetAgent.Callback {
override fun onGetResult(url: String, result: String?, error: String) {
if (result != null) {
continuation.resume(result)
} else {
continuation.resumeWith(Result.failure(IOException(error)))
}
}
}
requestingHashMap[url] = cb
iosHttpGetAgent.value!!.httpGet(url)
}
}
While on the swift code.
func httpGet(url: String) {
let task = URLSession.shared.dataTask(with: URL(string: url)!) { (data, response, error) in
if let resultData = data {
DispatchQueue.main.async {
ActualKt.notifyHttpGetResponse(
url:url,
result: String(data: resultData, encoding: .utf8)!,
error: "success")
}
} else {
DispatchQueue.main.async {
ActualKt.notifyHttpGetResponse(
url:url,
result: nil,
error: "success")
}
}
}
task.resume()
}
So kotlin/native code runs totally on the main thread.
Running totally on the main is the only solution for now. You can track #829 which will slightly expand your options and you'll be able to run coroutines separately on each threads (no easy way to communicate, though).
Hi, any progress on this issue? Or any possible solution for this issue? @elizarov
I'll be glad to know about this. thanks.
I'm also very concerned about this.
Well, the current state of multithreading in K/N is not really suitable for coroutines, the simple fact of giving a Continuation to a worker freeze the continuation, thus freezing the captured state and making it immutable (and pretty much unsuable).
For me multithreded coroutines is simply impossible with the current model.
@SeekDaSky I am not very experienced with K/N's concurrency model nor with the way, coroutines work under the hood, but I would also want to see support for multi-threaded coroutines in K/N.
Isn't there a way to make the continuation an immutable object that passes a new copy with the new state to the next K/N worker?
If I understand correctly you could detach the continuation and keep it mutable, but the state would not be accessible from another worker, so we still can't share values between threads.
We could heavily use channels and the actor paradigm to avoid any variable being shared, but this could lead to some performance degradation.
And this is just the developper side, developing a dispatcher with the limitations of the current concurrency model probably is daunting.
No, this might be pretty naive, but wouldn't it be possible to capture the whole state of the coroutine in some structure (let's say a data class) and just pass a new copy to the next worker?
To achieve this I think you just have to detach the continuation and re-attach it inside the next worker but you still can't have two threads accessing the data at the same time. And this could lead to some weird side effect if you share a value between two continuations by mistake
And this could lead to some weird side effect if you share a value between two continuations by mistake
Would you mind explaining this a little? I would be super interested ☺️
Well if you have a value that get caught in two distinct continuation, for example if you have
two suspensions in two different methods that use the same property of an object, when the first continuation is detached, the second one will fail (because the shared value is now detached) and that would be a real pain to debug.
And I don't know what would happen if a value is detached, re-attach in a worker and then detached from another one, there is so much corner cases that could lead to unexpected behaviour.
Ah yeah, I got that, thanks! Obviously, the whole situation is way more complex than 'just expressing the state machine as an immutable structure', since you are able to access stuff outside of the scope of the suspending function itself.
So while I really appreciate the work and ideas that went into K/N's concurrency model, I would rather prefer some concepts that coroutines bring to the table. For me personally (and most likely for our team), it would be much easier to work with concepts like Actors in our common source than handling the differences between the JVM and K/N. The new concurrency model (as nice as it might be) seems counter-productive towards multiplatform to me 😞
Your concerns about K/N memory model are valid (and pretty precise). In the current memory model, it is almost impossible to introduce multithreaded coroutines (at least implement already introduced common part to work with shared memory) that share the same semantics as JS and JVM primitives.
Yes it is possible to implement a separate library with detach/freeze semantics, actors and channels, but its API surface will be far from perfect and its impossible to write a common code with such primitives without constant fear of accidental freezings, detaches and in a way that some parts of the K/N-specific API do not leak into common and JVM code, so this is not something we are going to do.
But there is another way to address this problem: changes in K/N memory model. I am not going to discuss these changes (yet), but this is what we are aiming to. After these changes, we will implement a proper multithreaded K/N part of kotlinx.coroutines
Thanks for the update @qwwdfsad, it seems to be a very great news! While the immutability check makes sense for a language like Rust where transfer rules are in the core of the language, it is very confusing in the case of K/N.
Looking forward to hearing about the memory model change!
@qwwdfsad ,
changes in K/N memory model ... we are aiming to ... multithreaded K/N part of kotlinx.coroutines
Is there an ETA?
@ildarsharafutdinov no, there is no public ETA beyond "we will see a prototype in this year"
well that's a kind of ETA, is there a discussion/KEEP/forum post/whatever about the upcoming changes in K/N memory model ? I saw some movement in the Worker API but nothing that would improve the current situation.
Running totally on the main is the only solution for now. You can track #829 which will slightly expand your options and you'll be able to run coroutines separately on each threads (no easy way to communicate, though).
I'm confused. Are we still limited to running coroutines only on the main thread? Issue #829, mentioned earlier, was closed, but I don't understand how it relates to running "coroutines separately on each thread".
I mean, that in the current version you can run coroutines separately in each thread.
I mean, that in the current version you can run coroutines separately in each thread.
Should that also work on iOS? Because a dispatcher like
object MainLoopDispatcher: CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
NSRunLoop.mainRunLoop().performBlock {
block.run()
}
}
}
mentioned here: https://github.com/Kotlin/kotlinx.coroutines/issues/470#issuecomment-414635811 and here https://github.com/JetBrains/kotlinconf-app/blob/master/konfios/konfswift/ui/UI.swift
will always just run on main thread.
That means if I do something blocking in my code (call a non optimized framework) my UI will still freeze. So I am still looking for a way to run a coroutine on a non-main thread so that we can do heavy computations in it like here: https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md#blocking-operations-1
While you can run different coroutines in different threads on Kotlin/Native now, there is no easy way to transfer data between threads in Kotlin/Native yet and withContext idiom to offload computation onto background threads would not work on Kotlin/Native as of now, because it entails accessing objects from different threads.
Okay got it, thanks for clarification.
there is no easy way to transfer data between threads in Kotlin/Native yet and
withContextidiom to offload computation onto background threads would not work
Actually, simple test shows that theses are not the only limitations. At least kotlinx.coroutines.delay suspend function is broken when called from non-main thread.
error output and sample code
version
kotlin version 1.3.20, coroutines version 1.1.1.
error output
zero delay works fine
non-zero delay fails with exception
kotlin.native.IncorrectDereferenceException: Trying to access top level value not marked as @ThreadLocal or @SharedImmutable from non-main thread
at 0 main 0x000000010a72fba6 ThrowIncorrectDereferenceException + 54
at 1 main 0x000000010a82a83e kfun:kotlinx.coroutines.delay(kotlin.Long) + 1870
at 2 main 0x000000010a58b782 kfun:example.BrokenDelayExample.$testDelay$lambda-1$COROUTINE$8.invokeSuspend(kotlin.Result)kotlin.Any? + 1346
at 3 main 0x000000010a7f03cc kfun:kotlinx.coroutines.DispatchedTask.run() + 3004
at 4 main 0x000000010a58c859 kfun:example.BrokenDelayExample.CurrentLoopDispatcher.$$FUNCTION_REFERENCE$11.invoke#internal + 89
at 5 main 0x000000010a937aa9 __platform_Foundation_kniBridge8343_block_invoke + 25
at 6 CoreFoundation 0x000000010d2b062c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
at 7 CoreFoundation 0x000000010d2afde0 __CFRunLoopDoBlocks + 336
at 8 CoreFoundation 0x000000010d2aa62e __CFRunLoopRun + 1246
at 9 CoreFoundation 0x000000010d2a9e11 CFRunLoopRunSpecific + 625
at 10 Foundation 0x000000010b731322 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 277
at 11 main 0x000000010a937855 platform_Foundation_kniBridge8340 + 85
at 12 main 0x000000010a58a045 kfun:example.BrokenDelayExample.$$FUNCTION_REFERENCE$10.invoke#internal + 1765
sample code
package example
import kotlinx.coroutines.*
import platform.Foundation.*
import kotlin.coroutines.CoroutineContext
import kotlin.native.concurrent.freeze
class BrokenDelayExample {
fun run() {
run(::testDelay)
}
private fun run(block: () -> Unit) {
val blockWithRunLoop = {
block()
while (NSRunLoop.currentRunLoop.runMode(NSDefaultRunLoopMode, NSDate.distantFuture)) {
// loop
}
NSThread.exit()
}
NSThread(blockWithRunLoop.freeze())
.start()
}
private fun testDelay() {
CoroutineScope(CurrentLoopDispatcher() + Job())
.launch {
delay(0)
println("zero delay works fine")
try {
delay(50)
} catch (ex: RuntimeException) {
println("non-zero delay fails with exception")
ex.printStackTrace()
}
}
}
class CurrentLoopDispatcher : CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
NSRunLoop.currentRunLoop().performBlock { block.run() }
}
}
}
Unfortunately, that is true.
Regarding memory ownership and concurrency issues, I really wish that Kotlin would handle "fearless concurrency" in a better way and more generally provide mechanisms like "exclusive class" like Rust. Even Swift is slightly moving into that direction.
There are some non-trivial compromises with respect to other langauge features:
Swift requires manual annotation of weak references, providing only limited form of automated garbage collection (only for non-cyclic garbage). Another compromise is that Swift programs corrupt memory (crash/coredump) on data race. We consider the later to be acceptable compromise, but not the former. We do belive in fully automatic memory management.
Rust requires additional ownership annotations from developer. It forces developers to explicitly think about memory ownership and its transfer, so that you can have explicit control on memory allocations, but in a safe way. This is a great feature for an systems language, but we do belive that it is an extraneous concern for application developers that Kotlin targets.
Thanks for the clarifications. The clear language design and its differentiation from Swift and Rust perfectly make sense.
Regarding compromises and runtime exceptions (vs manual annotations), the way optionals have been introduced into the language may be the perfect example to follow. While Java's null pointer exceptions did not bring much more (besides security aspects) than C/C++'s segmentation faults, the introduction of (semi-) manual annotations for optionals ('?') did definitly succeed to eliminate the issue without any significant drawback regarding ease of use.
Of course racing conditions is a much more complex problem to solve and the analogy with null pointers may not be completly fair but I still hope that the issue could be eliminated in an elegant way. (Optionally) marking instances and (their references) as mutable vs read-only might be part of the solution but dealing with nested structures makes it hard to achieve that goal. The introduction of mutability concepts into the language is generally a very complicated challenge.
The runtime restrictions introduced in Kotlin/Native (together with the possibility to freeze objects) is probably what confused the most as it adds strong restrictions (i.e. this issue) without solving the real problem. I would be personally happy enough if the new memory model could relax those restrictions, allow (unsafe) concurrent access to instances and keep the language consistent with its JVM variant.
I concur, the forced immutability in order to share data between threads is single handedly the most frustrating aspect of K/N (I recognize there are ways around it, but none of them are desirable). Solving race conditions isn't a problem I want the language to solve for me, personally. I believe platforms have sufficient mechanisms for this already. It massively breaks what I want from the multiplatform paradigm I was hoping for from Kotlin. Specifically between iOS & Android. I otherwise think it's great and will continue to use it. I'll just grumble more than I would otherwise like.
I'll add the dissenting point here. I don't like all aspects of the native concurrency, but I like the general direction, and I think simply reintroducing unsafe memory access to conform to the JVM would be a lost opportunity. I do think not having MT coroutines is very frustrating, but just dumping the concurrency constraints isn't the answer.
"adds strong restrictions (i.e. this issue) without solving the real problem"
I think it solves the problem of runtime verification of safe concurrent access, which is the point. How all these things resolve, we'll see, but if we're expressing desires, I vote to not simply abandon the concurrency efforts.
UPDATE: Currently, coroutines are supported only on the main thread. You cannot have coroutines off the main thread due to the way the library is currently structured.
Is this still accurate? Is it not possible to use runBlocking on a background thread to execute some coroutine code using an unconfined dispatcher? I'm looking for a short term workaround to be able to write our code using coroutines, but still run it on a background thread (don't mind doing the work to ensure it all runs on one thread). Something along the lines of:
worker.execute({}) {
runBlocking(Dispatchers.Unconfined) {
launch {
// do work
}
}
}
Okay so I tried that ^. You can get it to work sometimes, but it's extremely fragile. Eventually, you run into coroutines internals that aren't thread safe, and then it blows up. FWIW, this exercise made me more excited/happy about the native concurrency model. It caught a bunch of problems quickly, without which I would have likely built complex concurrency stuff on top of fragile code. Anyway, can't wait for multi-threaded coroutines 🎉
@benasher44 could you please elaborate what machinery does not work in the worker?
I would be grateful if you could create an issue for that as this problem is expected to be fixed in #826
Will do. I’ll spend today and tomorrow recreating this and trying to file issues. Thanks!
Actually it works fine. I think yesterday I put myself in some weird scenario using multiple threads and Dispatchers.Unconfined. I started fresh today, and something like this works in a test:
// helper entrypoint into a worker context coroutine
fun Worker.launch(block: suspend CoroutineScope.() -> Unit) {
block.freeze()
execute(TransferMode.SAFE, { block }) {
println("executing")
runBlocking(block = it)
}
}
class NativeCoroutineTest {
@Test fun `bg coroutine test`() {
val worker = Worker.start()
worker.launch {
println("started")
launch {
println("launch 1")
}
println("test delay")
delay(10)
println("test delay done")
}
runBlocking {
// hang the test to give worker room to run
delay(10000000000)
}
}
}
The main issue we run into on native in this scenario is if we go out the the client app to have it make a network request and suspend the worker (or any) coroutine in the process, there doesn't seem to be a way to resume with the result of that network request back into the worker thread. I think the ability to do that falls into the feature "Support multi-threaded coroutines on Kotlin/Native," which brings me back here 😅. Do I understand that correctly? If there were a way to do exactly that in the short term (~i think this means making the event loop thread safe~), then that would be super helpful. The answer here in JVM I think would be to use withContext(otherThreadsContext) to then resume in the original context, but there doesn't appear to be a way to reference another thread's context from another thread.
The problem is not withContext(otherThread) { ... } per se. The problem is that in this way you start sharing data between this and other thread and the only solution K/N offers now is to freeze the data you share. It works for some use-cases but does not cover the cases where you need to transfer data that is mutable.
Right the mutable data part is understandably tricky, and I look forward to seeing that hashed out. In my particular scenario, I’m making a network request and suspending a coroutine running on a worker thread. The network request returns to the call site on a different thread. Getting from the network thread back to the coroutine thread turned out to be really difficult because a continuation cannot be frozen (gets mutated on resume) nor detached (referenced somewhere by internal coroutine machinery). I managed to get to a solution that uses a @ThreadLocal variable to hold onto the continuation, which I can then resume after freezing the network data and transferring it back to the coroutine thread. I’ll post the somewhat generalized solution today or Monday. This could be made a lot smoother if continuations were atomic (I.e. allow passing them around threads, even if it’s only legal to resume them on the original thread). Is that something worth ticketing, which would be done before the full solution for this issue?
Making continuations atomic is hard for the same reason, as you resume continuation with a value and that value has to be somehow transferred to another thread.
I agree, but in that case it's the responsibility of the client code to manage getting that value across threads, for which K/N already provides facilities (freeze, DetachedObjectGraph). The issue here is that I can manage safely transfering the object/value that I own outside of kotlinx.coroutines, but I have no recourse for passing the continuation across threads with the intent to eventually bring it back to its original thread to then resume it (i.e. basically want to be able to bring it across threads and promise that i'll do the right thing and only resume it on the original thread where it was suspended) because they (continutations) can't be frozen or detached.
But the problem is that if Continuation is atomic, then you can only resume it with frozen objects even if your coroutines are in single-thread only. K/N memory model only allows you to store frozen objects in atomic references.
There is no way to make continuation "conditionally atomic". Alternatively, we can do massive copy-paste and have two parallel hierarchies of all coroutine classes -- atomic for cross-thread and regular for single-thread usage. This is a non-starter either.
But the problem is that if Continuation is atomic, then you can only resume it with frozen objects even if your coroutines are in single-thread only. K/N memory model only allows you to store frozen objects in atomic references.
There are some common (imo) cases (the particular ones i'm dealing with 🙂) where this concession is okay:
Alternatively, we can do massive copy-paste and have two parallel hierarchies of all coroutine classes -- atomic for cross-thread and regular for single-thread usage. This is a non-starter either.
I agree with you there. That sounds like a nightmare (wish I had more to offer/say around how this complexity could be managed, but I haven't spent enough time digging through continuation code to be able).
I don't understand the implications of the current state of kotlin-native. Is it doable to implement the following use case?
1) In the UI thread, pass a request object to a background thread
2) In the background thread, start a long polling task (like http call) and get a response object
3) Pass the response to the UI thread
In this scenario, it's perfectly ok to freeze the request and response objects.
Thank you
What is the status of this right now?
Guys, are there any updates?
No updates yet.
We will post here as soon as there will be any.
I think this commit might be extremely interesting/promising! ☺️
olonho: _Very preliminary relaxed mode draft._
https://github.com/JetBrains/kotlin-native/commit/81eb6b2be689591b4bd697464c910afdc0f2a456
(MemoryModel.RELAXED)
I have my doubts about this, K/N devs are really reluctant about this mode (and they are right to be), it certainly will need some kind of background GC to collect cyclic references and this will affect K/N performances quite a bit.
Plus, if you give devs an easy and known way (no control from the language about what you do with your mutable states), they WILL choose it over the standard "strict" memory model.
Unfortunately, if they decided to go this way, it's probably because they have no other options to have a proper kotlinx.coroutines implementation that is unified for all platforms.
also : https://discuss.kotlinlang.org/t/kotlin-native-1-3-50-relaxed-mode/13586/5
I absolutely get your point and I also think the ideas that went into the new (strict) memory model are great. However, I think the multiplatform aspects of Kotlin just outweigh the benefits of the strict memory model! I think the solution with the flag is pretty elegant: K/N only project can still keep the strict mode, while multiplatform projects can use the relaxed mode (which just makes sense for this use case, considering the platforms you compile to: iOS/Swift, jvm/Java, ...)
I agree you can't have multiplatform without a relaxed memory model, I simply hope that pure K/N project will keep using the strict mode and not use relaxed. It is still very experimental at this point so wait and see.
@sellmair Agreed! Maybe like what java have done, with the strict memory model, we can still provide an unsafe mechanism, which is "unsafe" obviously but provides better performance and more flexibility.
Programer is encouraged to use strict memory model, but still have the freedom to do unsafe stuff and of course, take their own responsibility.
This may be applied to Kotlin/Native too.
K/N provides Saner Concurrency model alongside traditional _unsafe_ one. Common programmers use the Saner one, while advanced programmers may use the _unsafe_ one to meet their performance requirement(s). As we have seen from other languages, the Saner model can be built on top up the _unsafe_ one inside the standard library. And also, as for coroutines can be, of course, built on top of the _unsafe_ APIs.
@LanderlYoung I don't think the unsafe model memory will be more performant, in the contrary it needs a fully functional GC able to detect cylic references in a multi-threaded program, which is not an easy task (the JVM have been struggling with their GC's for years). The strict model provides a way to manage memory without this because references explicitly can not be in two threads at a time, making it easy to collect (cf. Rust that doesn't even have a GC and still manage memory automatically, kinda).
I think performance is not even a big point here. It's more about the overall big picture (multiplatform). Also, obviously, there are scenarios where you could find each memory model to outperform the other (GC might be easier/more performant on strict mode, multi-threaded matrix multiplications might be easier/more performant on relaxed mode). But let's keep in mind, that Kotlin identifies as an application language. I am looking forward to the next steps. For our team, multiplatform seems extremely promising!
"Common programmers use the Saner one, while advanced programmers may use the unsafe one" I think you'd find the opposite would happen in practice, as the advanced programmers are generally the ones who would know why you want to use the "Saner" one.
"I think the solution with the flag is pretty elegant: K/N only project can still keep the strict mode" We'll see how it goes, but I think if there's a "relaxed mode" you'll see "strict mode" go away. Pretty much all apps, K/N-only or multiplatform, will need libraries, and relaxed and strict libraries won't really work together (easily). We'll (probably) need a way to fail builds if you're trying to use a relaxed library in strict mode. That kind of thing. Formally adding relaxed mode will be a big shift. It wouldn't be the first time I was wrong in life, but that's my guess. It just seems like maintaining both modes, across many platforms, while also optimizing the builds and runtime is going to be a lot of overhead.
Relaxed mode will definitely impact performance for the foreseeable future. "How much" is a big question, of course, but it will. Memory management is a big part of the performance in KN apps, and there are thread confined assumptions you can no longer make.
Not a vote for or against relaxed mode (and there isn't an election anyway). Just saying I'd bet on strict mode going away if you need to compile with relaxed mode for kotlinx.coroutines (and other libraries).
I've just listened to Andrey Breslav talk about multi-threaded coroutines and Kotlin/Native memory safety in Episode 119 of Android Developers Backstage.
It seems the biggest struggle is regarding iOS/macOS background queues that give no guarantee to which thread they will run on, while threads are kind of deprecated here.
So, here's a path to a solution I found while listening:
Allowing to wrap a dispatch queue as a CoroutineDispatcher (much like done for Android's Handler), which does the following:
⮑Any access to involved mutable data in a timeframe where there's no thread association would lead to an Error or an Exception to be thrown.
⮑Any access to involved mutable data on a thread different from the one currently being run by the dispatch queue would also lead to an Error or an Exception to be thrown.
Each time the CoroutineInterceptor (usually a CoroutineDispatcher) is changed, transfer ownership of the involved mutable data in the same way you would for a native platform that doesn't have kind of deprecated threads.
Mutable data thread ownership could be controlled by new experimental/internal/restricted APIs in Kotlin/Native, which would still check you remove ownership before adding a new ownership, or swap it atomically. That would prevent people from turning these facilities into shared mutable data, and we would keep the mind relaxing "Shared XOR Mutable" paradigm.
JetBrains folks have probably thought about this, and I'm certain it's not as easy as it might seem, but it might interest people following this issue.
@LouisCAD In fact, we are going to experiment with multiple solutions for iOS dispatcher. On one side, we'll provide an implementation of newSingleThreadContext that creates "deprecated threads" and just confines all the code there. On the other hand, we'll provide ability to convert an iOS sync queue to a coroutine dispatcher using "detached object graph", which allows to do what you've described -- to transfer a graph of objects to another thread.
@elizarov I assume that when you say iOS, you mean iOS (+iPadOS) and macOS?
macOS compatibility is very helpful to run tests without spawning a simulator.
About threads, I stumbled upon Apple documentation and found they are not deprecated (that word is not used anywhere). It's only that their usage is discouraged (by words) in favor of Grand Central Dispatch (aka. GCD) for four reasons that I'm quoting:
The first point certainly applies in coroutines case as I assume GCD keeps threads in the OS and only creates them as apps block them but more are needed (includes NSOperation when it's sitting on top of GCD).
However, all the three remaining points don't apply for kotlinx.coroutines users.
Here are all the relevant docs I found for interested people:
The problem with using GCD and coroutines together is that GCD queues don't guarantee the threads they run on. They only guarantee synchronization with respect to the queues you run your blocks on, which doesn't mesh with the current thread-ownership model of K/N. IMO, NSOperation should be avoid in the context of coroutines. It's a higher level system for writing application-level worker tasks.
Furthermore, the thread efficiency gains really come from carefully constructing GCD queue hierarchies and keeping a fixed number of them in your application. See this WWDC talk from 2017.
When comparing systems, coroutines and GCD are _roughly_ the same level of abstraction (with respect to threads), and I'd expect thread management to be more successful if that weren't delegated from coroutines to GCD and instead handled by coroutines itself.
@elizarov Can I politely enquire yours/JetBrain's current position on this issue?
The interest it's received - both above and on kotlinlang Slack - shows its importance for many multi-platform users, while this thread has not been updated in 2 months and is now marked as _postponed_, with no assignee or any mention in any 1.4 road-map etc. that I can find.
Would be good to have some idea whether JetBrains still consider it a relevant issue as it may affect our adoption of K/MP for mobile.
Pro-active question: If I were to go ahead and implement a Dispatcher that rested on NSThread or underlying pthread API's (and not GCD), with the understanding that my application-level design would need to respect object freezing across threads; is there any other obvious blocker to doing so? i.e. Is it the coroutine internals themselves that would breach object freezing rules and cause this 'naive' approach to immediately fail?
@chris-hatton It is still relevant and is still in our roadmap. The challenge is exactly in making all the coroutine internals compatible with freezing, that is making sure that objects like Job can be freely shared across threads.
@elizarov So does that mean, that we can assume that the relaxed memory model is off the table now? I am still convinced, that the current native memory model is harming multiplatform massively.
@sellmair Relaxed memory model is also work in progress.
To give you some more detail on what's holding us back. kotlinx.coroutines is a multiplatform library. Currently all the "multithreading-capable" data structures are part of JVM compilation only while Native and JS contains simple stubs. In order to support multi-threading on Native we need to share this code between JVM and Native, while leaving stubs for JS. Unfortunately, our current MPP model in Kotlin (which is still experimental) does not support this. We are working on its next version code-named "Hierarchical MPP" (HMPP) which enable this kind of fine-grained sharing.
Currently, coroutines are supported only on the main thread. You cannot have coroutines off the main thread due to the way the library is currently structured.
Is this true - I just thought all coroutines need to run on the same thread? If so, could we have all coroutines run on a separate, single background thread?
@ZakTaccardi
That is not the case, and has not been since the beginning of this library. The idea has been on the radar since inception but as @elizarov reminds us, the problem is to make multi-threaded work possible outside of the JVM where we are capable of having coroutines on multiple threads already.
There are many capabilites for doing structured synchronous work through the current API, but there are limitations. Such as if you want to resolve values and elevate them out of an async scope, you have very few options for the Non-JVM api's such as callbacks. My team has chosen this as our current solution, and because suspend functions are erased for non-jvm compilation targets, we just overload the signatures with the same name expecting callback functions for all other targets. When we reach feature parity between the platforms it's very little client work to update our clients from callbacks to the structured synchronicity as well as the consistent api exposure.
I'd rather JetBrains take a cautious approach to solving this issue and give us strong architecture with consistent api's than release volatile tools right now.
@elizarov Couldn't you guys just copy it over the data structures for now to Kotlin/native to unblock yourselves :P. Sounds pretty trivial to clean up later once HMPP comes out.
@ScottPierce We've been through that experience when we first introduced MPP into kotlinx.coroutines at at time when there was no real MPP support in Kotlin. It becomes a nightmare to maintain.
Is the Hierarchical MPP expected to be released anytime soon? (this year? sometime in 2020?)
Also, for my use-case, I don't really need multithreading, I just need everything to not be on the main thread. Is it currently possible to use just one background thread for everything? Or do I need to wait for the HMPP? (or is this not at all related?)
@NinoScript There is a PR multi-threaded coroutines for Kotlin/Native out already based on 1.3.60. I assume that update had what was needed. You can take a look at the draft PR here.
I was able to build it locally, release it to maven local, and try it out. With the automatic freezing of objects, it feels pretty good.
I’ve published the first development preview version of multi-threaded kotlinx.coroutines version 1.3.2-native-mt-1 for Kotlin/Native (version 1.3.60) . Make sure to study the docs before using it:
https://github.com/Kotlin/kotlinx.coroutines/blob/native-mt/kotlin-native-sharing.md
Great to see official support on the way.
Others in the thread might be interested in https://github.com/Autodesk/coroutineworker until that arrives, it's working pretty well for us (I'm not affiliated with Autodesk).
Is it possible to use coroutine or worker to implement the message queue pattern?
"message queue pattern" means: an object, let's call it Counter, provides some operations, e.g. increase and decrease, these operations could be called from main thread or other worker threads, but Counter will schedule these calls into its own single threaded message queue, then change its state, e.g. the count, it may also output its state through some callback, and the callback should be invoked on main thread.
On Android, we could using Handler or Executor to implement this pattern easily, I'm thinking if it's possible to do it on Kotlin/Native. I want to develop a Kotlin multiplatform app and want to use this pattern in it.
Sorry if this question is off-topic, but I really can't find a better place to ask it.
@Piasy You can ask on https://slack.kotl.in or here, but in a new issue.
I've published version 1.3.3-native-mt to Bintray with the updated version of the branch for native concurrency on top of kotlinx.coroutines 1.3.3 and Kotlin 1.3.61.
@elizarov Hi, can I ask a question? When I used Mutex with coroutines(1.3.3-native-mt), I found the Mutex would make a coroutine suspend and not resume, but the similar code will be work that run with Kotlin/JVM. Is this a bug? The code is shown in following:
fun main() = runBlocking {
val testData = TestData()
val bareTestData = DetachedObjectGraph(TransferMode.UNSAFE) { testData }
val mutex = Mutex()
val job = launch(Dispatchers.Default) {
val outTestData = bareTestData.attach()
repeat(20000) {
mutex.withLock { outTestData.index++ }
}
}
repeat(20000) {
mutex.withLock { testData.index++ }
}
job.join()
println(testData.index)
}
data class TestData(var index: Int = 0)
The similar code run with Kotlin/JVM:
fun main() = runBlocking {
val testData = TestData()
val mutex = Mutex()
val job = launch(Dispatchers.Default) {
repeat(20000) {
mutex.withLock { testData.index++ }
}
}
repeat(20000) {
mutex.withLock { testData.index++ }
}
job.join()
println(testData.index)
}
data class TestData(var index: Int = 0)
Is this idea ever considered to be included in Kotlin? https://itnext.io/designing-a-kotlin-memory-safe-mode-c76c06317c3e
It is a very good idea IMHO...
Is this idea ever considered to be included in Kotlin? https://itnext.io/designing-a-kotlin-memory-safe-mode-c76c06317c3e
It is a very good idea IMHO...
I read that article a while ago and it feels like the way to go, I guess the author could post a KEEP and see what the Kotlin devs think about it
You'd have to finish the design first. All types would need to be const or not const, and you couldn't cast between them, so that would mean ditching the entire standard lib and starting over, and probably giving up on JVM interop.
"The next question is about polymorphism. Can we extend const classes? Are const interfaces allowed? If so, are all of their implementations required to be const?
These are very relevant questions, but irrelevant in the scope of this article."
I'd say they're critical to any proposal to change the language.
I've seen this post come up a few times recently, but it's unrealistic and doesn't address some of the serious issues that would need to be addressed. How well would Kotlin fare in the JVM world when a huge portion of the JVM runtime would be rendered incompatible? We could say JVM runtime is given special dispensation to break the rules, bu then what's the point?
That, of course, has nothing to do with MT coroutines. Discussing core language changes is probably best done elsewhere.
@elizarov Is there a version of 1.3.3-native-mt that's compatible with 1.3.70?
Is there a version of
1.3.3-native-mtthat's compatible with 1.3.70?
Not yet. I'll post here when it becomes available.
@elizarov I noticed this is marked postponed. It's been close to 4 months now. I'm surprised we haven't seen this released yet. Any update you can share about what's going on?
@ScottPierce There's work-in-progress in #1648, you can read the documentation in this (currently draft) PR. There's also some publications done as possible (not done for 1.3.70 yet because of a new memory leak that has a workaround until it gets fixed for real in Kotlin/Native).
I think it's postponed until Kotlin/Native is fully ready to have it work well, without memory leaks, but it's already iterating.
Any updates(1.3.4-mt publication)? It has been blocking my 1.3.70 migration
@LouisCAD , do u have link for Kotlin native issue? Saw some commits about memory leaks detector etc
@IgorKey Here you go: https://youtrack.jetbrains.com/issue/KT-37232
I don't think you can expect another native-mt release before the related PR is merged and makes it to a new Kotlin release (probably 1.3.71).
Unfortunately because our IDEA plugin version and Gradle plugin version must be equivalent, if we use this library in any one of our projects, then none of them can be upgraded to 1.3.70.
k/N 1.3.71 has just come) https://github.com/JetBrains/kotlin-native/releases/tag/v1.3.71
Leak problem solved
📣 kotlinx.coroutines version 1.3.5-native-mt is available for Kotlin 1.3.71.
@elizarov could you point me to where we can find the new version? I can't find it on maven.
@kar It is on jcenter (https://bintray.com/package/info/kotlin/kotlinx/kotlinx.coroutines)
Thanks. I've just uploaded it to Maven Central, too.
📣 kotlinx.coroutines version 1.3.5-native-mt-1.4-M1 for those of you using Kotlin 1.4-M1.
@elizarov I just filed a potential bug with the native-mt version of coroutines / Flow here: https://github.com/Kotlin/kotlinx.coroutines/issues/1895
Since this seems to get stable now, are there any plans / estimations, when something like newSingleThreadContext will be implemented? Is there a convenient way to achieve such thing already?
Hi guys, I'm trying to use the 1.3.5-native-mt with ktor, but I'm getting this error:
HttpClient: REQUEST URL failed with exception: kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen io.ktor.util.pipeline.Pipeline.PhaseContent@a7fe18
Uncaught Kotlin exception: kotlinx.coroutines.CoroutinesInternalError: Fatal exception in coroutines machinery for AwaitContinuation(Shareable[used]){HttpResponseData=(statusCode=200 OK)}@27e9c78. Please read KDoc to 'handleFatalException' method and report this incident to maintainers
I'm not pretty sure if this error should be reported to ktor guys or here, my class looks like this ->
class Remote {
val client = HttpClient()
suspend fun getData() = client.get<Data>()
}
I suppose that this is because I'm not creating Remote instance on the bg thread, Am I right?
@sergiocasero ktor is not compatible with the MT coroutines. We have a very hacky workaround here until they are compatible. The summary is you can use ktor as long as you don't freeze the Job in your context. https://github.com/touchlab/KaMPKit/blob/master/shared/src/iosMain/kotlin/co/touchlab/kampstarter/ktor/Platform.kt
Thanks @kpgalligan :), But if I understand, the workaround executes the ktor calls on the main thread, right?
@sergiocasero ktor calls are suspending. The call starts on the main thread, but then suspends and the underlying networking will happen async. When the call is complete, your code will resume on the main thread. So, it won't block on the main thread, but our calls start there. We haven't tried doing all that on a different thread, but haven't needed to (because the calls suspend).
jmmm, I think I understand you, thanks @kpgalligan :)
@kpgalligan do you by any chance know an issue on the ktor bugtracker I can subscribe to in this regard?
@dimsuz I think this is the issue created by @kpgalligan related to ktor.
Are there any plans to push a new native-mt version for coroutines 1.3.7 and kotlin 1.3.72? Unless I'm missing something it doesn't seem like there's a published version that includes the recent addition of StateFlow. I've had some curiosity and want to try it out on iOS.
Hi,
First thank you for all your work. Great stuff.
I am new to coroutines, but I think I have a grasp of things already.
If I am not using them correctly in below examples please correct me.
For below native example I used:
1.4-M1
and
1.3.5-2-native-mt-1.4-M1
Native:
fun main() = runBlocking {
val durationInSFirst = 2
val durationInSSecond = 1
launch(Dispatchers.Default) {
platform.posix.sleep(durationInSFirst.toUInt())
println("resumed first", coroutineContext)
}
println("launched first (block for ${durationInSFirst}s)", coroutineContext)
launch(Dispatchers.Default) {
platform.posix.sleep(durationInSSecond.toUInt())
println("resumed second", coroutineContext)
}
println("launched second (block for ${durationInSSecond}s)", coroutineContext)
}
private fun println(msg: String, coroutineContext: CoroutineContext) {
println("${getTimeMillis()} $coroutineContext: $msg")
}
prints:
932193135: launched first (block for 2s) | [BlockingCoroutine{Active}@4ad05e68, ShareableEventLoop@4ad05ba8]
932193135: launched second (block for 1s) | [BlockingCoroutine{Active}@4ad05e68, ShareableEventLoop@4ad05ba8]
932195138: resumed first | [StandaloneCoroutine{Active}@4ad06198, WorkerCoroutineDispatcherImpl@4ad05d68]
932196143: resumed second | [StandaloneCoroutine{Active}@4ad07588, WorkerCoroutineDispatcherImpl@4ad05d68]
JVM:
fun main() = runBlocking {
val durationInSFirst = 2
val durationInSSecond = 1
launch(Dispatchers.Default) {
Thread.sleep(durationInSFirst * 1000L)
println("resumed first", coroutineContext)
}
println("launched first (block for ${durationInSFirst}s)", coroutineContext)
launch(Dispatchers.Default) {
Thread.sleep(durationInSSecond * 1000L)
println("resumed second", coroutineContext)
}
println("launched second (block for ${durationInSSecond}s)", coroutineContext)
}
private fun println(msg: String, coroutineContext: CoroutineContext) {
println("${System.currentTimeMillis()} $coroutineContext: $msg")
}
prints
1592129905337: launched first (block for 2s) | [BlockingCoroutine{Active}@5eb5c224, BlockingEventLoop@53e25b76]
1592129905341: launched second (block for 1s) | [BlockingCoroutine{Active}@5eb5c224, BlockingEventLoop@53e25b76]
1592129906342: resumed second | [StandaloneCoroutine{Active}@57265a91, DefaultDispatcher]
1592129907338: resumed first | [StandaloneCoroutine{Active}@7cc3330e, DefaultDispatcher]
Please notice the difference in the order of the two last lines of the output.
Is Dispatchers.Default on Native backed by a single thread at the moment?
@gswierczynski
Is Dispatchers.Default on Native backed by a single thread at the moment?
Yes, it is even documented in #1648
@LouisCAD Got it, thanks
Documentation: https://github.com/Kotlin/kotlinx.coroutines/blob/native-mt/kotlin-native-sharing.md
A Default dispatcher on Kotlin/Native contains a single background thread. This is the dispatcher that is used by default in GlobalScope.
This limitation may be lifted in the future with the default dispatcher becoming multi-threaded and/or its coroutines becoming isolated from each other, so please do not assume that different coroutines running in the default dispatcher can share mutable data between themselves.
📣 UPDATE: Version 1.3.7-native-mt-1.4-M2 is released — the fresh update of native-mt for Kotlin 1.4-M2. For leak-free operation, this version should be used with a specially patched version of Kotlin: 1.4-M2-eap-23 (it differs from stock 1.4-M2 in Kotlin/Native only).
This version includes fixes for additional bugs discovered by native-mt early adopters (thanks a lot for all of you ❤️):
awaitAll in multi-threaded scenarios (#2025)FreezingException does not break coroutine machinery (#2064)The code is now based on the new features available in Kotlin/Native 1.4 (namely WorkerBoundReference) and there will be no more updates from native-mt branch for Kotlin 1.3. We plan to include the code from native-mt branch into the default kotlinx.coroutines distribution as Kotlin/Native version of the library for upcoming Kotlin 1.4 release.
Edit: After a few more tries, I finally found a version that worked. I figured it out once I realized StateFlow seems almost designed for something like an actor and that lead me to where I needed to go.
Decided to give version 1.3.7-native-mt-1.4-M2 a spin to see if I can make use of StateFlow on iOS, but can't seem to find the right combination (tried numerous variations) to set StateFlow without getting the InvalidMutabilityException. Any ideas on how I could make this work? The error gets thrown in the call to stateSetter. I based the organization of flow execution from the docs on flows, and specifically the section flowOn from here https://kotlinlang.org/docs/reference/coroutines/flow.html
typealias Reducer<TState> = (TState, Action) -> TState
@OptIn(ExperimentalCoroutinesApi::class)
open class KStore<TState:Any>(initialState: TState, private val reducer: Reducer<TState>) {
private val state = MutableStateFlow(initialState)
private fun currentState() = state.value
private fun setState(newState: TState) {
state.value = newState
}
fun dispatch(action: Action) {
val currentGetter: () -> TState = ::currentState
val stateSetter: (TState) -> Unit = ::setState
val stateChanges = when(action) {
is FlowAction -> action.toFlow()
else -> flow { emit(action )}
}.map {
reducer(currentGetter(), it)
}.flowOn(Dispatchers.Default)
println("Got state changes")
stateChanges.onEach {
stateSetter(it)
}.launchIn(UIScope())
}
//callback method for pushing back to swift, hopefully a better alternative can be found
fun listen(onStateChange: (TState) -> Unit) = runBlocking {
state.onEach {
onStateChange(it)
}.launchIn(UIScope())
}
}
We plan to include the code from
native-mtbranch into the defaultkotlinx.coroutinesdistribution as Kotlin/Native version of the library for upcoming Kotlin 1.4 release.
@elizarov does that mean that the native-mt branch will be merged into master or will it be a separate package that can only be used on Kotlin/Native? Would it still be possible with Kotlin 1.4 to use the native-mt code on JVM/Android? The native-mt branch fixes a crash on Android devices so it would be great if it could be used on JVM/Android as well. See: https://github.com/Kotlin/kotlinx.coroutines/pull/1648#issuecomment-617143634
We plan to include the code from
native-mtbranch into the defaultkotlinx.coroutinesdistribution as Kotlin/Native version of the library for upcoming Kotlin 1.4 release.@elizarov does that mean that the
native-mtbranch will be merged into master or will it be a separate package that can only be used on Kotlin/Native? Would it still be possible with Kotlin 1.4 to use thenative-mtcode on JVM/Android? Thenative-mtbranch fixes a crash on Android devices so it would be great if it could be used on JVM/Android as well. See: #1648 (comment)
We don't plan to merge all the code from native-mt in the master, but gradually work on porting its pieces. Only native code will be built from native-mt branch to start with. It would be great if we can, at least, figure out the bytecode of which classes causes the crash, so that we can concentrate on moving those changes to master first.
@elizarov I still don't quite understand what should we expect with Kotlin 1.4 in regards to coroutines multi-threading support. 1.4 M3 was released 2 weeks ago with all major libs (ktor, serialization, non-mt couroutines). Coroutines mt version wasn't included. Still no official announcement when native-mt M3 is going to be released. If you plan to include native-mt in master with 1.4 release then why it's considered as a second class citizen now? Also could you explain exactly in what form coroutines-mt will be released with Kotlin 1.4 because I hardly understand what does it mean in regards to 1.4 - _We don't plan to merge all the code from native-mt in the master, but gradually work on porting its pieces._
@elizarov Is there a native-mt build for Kotlin 1.4-M3?
📣 Published version 1.3.8-native-mt-1.4.0-rc for Kotlin 1.4.0-rc
@elizarov Is this published for the kotlinx-coroutines-core-common module too?
@IanArb with new "hierarchical project structure" support that was added since 1.4-M2 (https://blog.jetbrains.com/kotlin/2020/06/kotlin-1-4-m2-released/) you only need dependency on org.jetbrains.kotlinx:kotlinx-coroutines-core
@IanArb with new "hierarchical project structure" support that was added since 1.4-M2 (https://blog.jetbrains.com/kotlin/2020/06/kotlin-1-4-m2-released/) you only need dependency on
org.jetbrains.kotlinx:kotlinx-coroutines-core
Thanks!
@elizarov more of an fyi (and in case there's any known workaround) but getting following when using 1.3.8-native-mt-1.4.0-rc in a macOS project built using XCode 12 beta (not seeing issue in XCode 11.6). Also not seeing issue with the nonnative-mt version.
Undefined symbols for architecture x86_64:
"__kernelrpc_mach_port_destroy_trap", referenced from:
_platform_darwin__kernelrpc_mach_port_destroy_trap_wrapper850 in common(result.o)
(maybe you meant: knifunptr_platform_darwin883__kernelrpc_mach_port_destroy_trap, _platform_darwin__kernelrpc_mach_port_destroy_trap_wrapper850 )
@joreilly I don't think it is related to kotlinx.coroutines.
Could you create a Kotlin issue? https://kotl.in/issue
We'll also need additional details about your project, let's discuss this in the new issue.
@SvyatoslavScherbina thanks, have created https://youtrack.jetbrains.com/issue/KT-40782
Do we have any change log and doc for 1.3.8-native-mt-1.4.0-rc build?
1.3.9-native-mt is here: mirror of 1.3.9 with the same changes in Native part as in previous -native-mt versions
Do you have any plan for a new native-mt version including fix #2025?
I can't use ktor log level BODY and ALL with 1.3.9-native-mt.
1.3.9-native-mt-2 was released and ktor is working without any problem on native target. 👍
Anybody has any idea why this issue exists in the mt version? https://github.com/Kotlin/kotlinx.coroutines/issues/2335
runBlocking is not the only problem, I also witnessed code not being executed in main code. In particular with nested withContext() blocks.
I filed this report https://youtrack.jetbrains.com/issue/KT-42898 which I am a bit surprised no one else is running into. Basically, what happens is that a child coroutine returning a new instance of a class causes that instance to be frozen, even when all coroutines run on the same thread. I wouldn't expect this.
Perhaps I'm doing something stupid. Would be awesome if someone on the team could have a quick look and determine whether this is just me or an actual bug.
May I have an ETA on a 1.4.x-native-mt release? This is blocking ktorio/ktor#2160, and as ktor seems to enforce strict coroutines version check on native, and I've already migrated my codebase to use shared flows, this is blocking my development.
As it's been two week since 1.4.0 I'm wondering if this will happen soon or if I should migrate back to 1.3.9 to unblock development...
Thanks 🙏
UPDATE: kotlinx-coroutines version 1.4.1-native-mt released.
Does this also fix this issue https://youtrack.jetbrains.com/issue/KT-38770 ?
Haven't tested it myself yet but am planning to do that tomorrow. Will update this thread with my results.
I might be missing something, when I create a MutableStateFlow but set the value I get an InvalidMutabilityException. The same code worked in 1.3.9. Has anyone else ran into issues?
@TrevorStoneEpic others are experiencing that issue as well, looks like #2138 was re-opened and is tracking it.
Released 1.4.2-native-mt
Does this also fix this issue https://youtrack.jetbrains.com/issue/KT-38770 ?
Haven't tested it myself yet but am planning to do that tomorrow. Will update this thread with my results.
I can confirm 1.4.2-native-mt does fix the issues we had with immutability exceptions!
@qwwdfsad Is there any plan to make a new release soon? Would appreciate one that incorporates #2477 and #2476. 🙇
1.4.3-native-mt is released
Calling suspended functions in Swift from a background thread causes an exception with Calling Kotlin suspend functions from Swift/Objective-C is currently supported only on main thread. Does it mean that we only can change threads in Kotlin native part of the code and have to call suspended functions from the main thread on Swift?
I am using 1.4.3-native-mt version.
Most helpful comment
📣 UPDATE: Version
1.3.7-native-mt-1.4-M2is released — the fresh update ofnative-mtfor Kotlin1.4-M2. For leak-free operation, this version should be used with a specially patched version of Kotlin:1.4-M2-eap-23(it differs from stock1.4-M2in Kotlin/Native only).This version includes fixes for additional bugs discovered by
native-mtearly adopters (thanks a lot for all of you ❤️):awaitAllin multi-threaded scenarios (#2025)FreezingExceptiondoes not break coroutine machinery (#2064)The code is now based on the new features available in Kotlin/Native 1.4 (namely
WorkerBoundReference) and there will be no more updates fromnative-mtbranch for Kotlin 1.3. We plan to include the code fromnative-mtbranch into the defaultkotlinx.coroutinesdistribution as Kotlin/Native version of the library for upcoming Kotlin 1.4 release.