Kotlin Native. Multithreading without Coroutines

 1 year ago
source link: https://medium.com/google-developer-experts/kotlin-native-multithreading-without-coroutines-56599ea33620
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Kotlin Native. Multithreading without Coroutines

In previous story we discussed how to use Coroutines for simple multithreading in Kotlin Native. This time we will talk about using native mechanism of Kotlin Native to deal with asynchronous work.

When we use Ktor library in our Kotlin Multiplatform app, we know that all asynchronous work is implemented under the hood with a help of Kotlin Native mechanism. Let’s take a look and try to apply it in our own network client.

At first, we will make a common interface for our iOS and Android Http clients. We will implement them differently, but without expect/actual mechanism:

We can use OkHttp to provide all the logic in androidMain. For iOS we will use NSUrlSession in iOSMain part of our common module. All the native frameworks (such as Network) are available and accessible for us in iOSMain.

We will use standard NSUrlSession approach with some delegate to receive response:

So, in this point we need to provide some mechanism to call our task from background. For this purpose Kotlin Native has Workers. A Worker is a job queue on which you can schedule jobs to run on a different thread. Every worker performs work in its own thread:

There are several details:
1. We need to use TransferMode.SAFE for thread-safe work.

2. We need to freeze a block of code to perform it in different thread. In my case, I use share() extension to incapsulate freezing.

As a result of execution we receive some Future. To deal with its completion and result value, we can use consume:

Also we can send the completion into some another thread. For example, it could be main thread and main queue:

That could be done the same way we previously used to create our own MainDispatcher.
Let’s apply it to our sample. Also we need to freeze all the parameters and blocks we will use within our client:

When we implement our own network client with a delegate approach, we can receive all the data as separated portions. So we need to use byte array to keep all the data together:

And there is a big problem. While freezing all the stuff of our client, we have frozen even the var variables. Now we cannot change our data without a crash.
To deal with it we need to use AtomicReference API. AtomicReferences hold the links to frozen variables, but allow to change their values:

There is a risk of potential leaks while using AtomicReferences. So we need to clear them after the work:

Done. Let’s call from our iOSMain side:

And it works without any Coroutines:

About Joyk

Aggregate valuable and interesting links.
Joyk means Joy of geeK