Introduction to Kotlin language foundation: Kotlin collaborative process foundation

Posted by laanes on Tue, 22 Feb 2022 15:34:19 +0100

1. Blocking and non blocking

runBlocking

delay is non blocking, thread Sleep is blocked. Explicitly use the runBlocking coroutine builder to block.

import kotlinx.coroutines.*
​
fun main() {
 GlobalScope.launch { // Start a new collaboration in the background and continue
 delay(200)
 "rustfisher.com".forEach {
 print(it)
 delay(280)
 }
 }
 println("The code in the main thread executes immediately")
 runBlocking {     // This expression blocks the main thread
 delay(3000L)  //Blocking the main thread to prevent too fast exit
 }
 println("\n End of example")
}

As you can see, runBlocking uses delay to delay. The main process using runBlocking will be blocked until the execution of the internal co process of runBlocking is completed. That is, runBlocking {delay} realizes the blocking effect.

We can also wrap the main function with runBlocking.

import kotlinx.coroutines.*
​
fun main() = runBlocking {
 delay(100) // You can use delay here
​
 GlobalScope.launch {
 delay(100)
 println("Fisher")
 }
 print("Rust ")
 delay(3000)
}

< unit > in runblocking < unit > can be omitted at present.

runBlocking can also be used in testing

// Introduce junit
dependencies {
 implementation("junit:junit:4.13.1")
}

unit testing

Set up a Test using @ Test

import org.junit.Test
import kotlinx.coroutines.*
​
class C3Test {
​
 @Test
 fun test1() = runBlocking {
 println("junit Test start ${System.currentTimeMillis()}")
 delay(1234)
 println("junit End of test ${System.currentTimeMillis()}")
 }
}

Operation results

junit Test start 1632401800686
junit End of test 1632401801928

IDEA may prompt no tasks available. You need to change the test option to IDEA, as shown in the following figure.

change setting

2. Wait

Sometimes it is necessary to wait for the execution of the cooperation process. You can use the join() method. This method will suspend the current process until the execution is completed. You need to use main() = runBlocking.

import kotlinx.coroutines.*
​
fun main() = runBlocking {
 println("Test wait")
 val job1 = GlobalScope.launch {
 println("job1 start")
 delay(300)
 println("job1 done")
 }
 val job2 = GlobalScope.launch {
 println("job2 start")
 delay(800)
 println("job2 done")
 }
​
 job2.join()
 job1.join() // wait for
 println("End of test")
}

Run log

Test wait
job1 start
job2 start
job1 done
job2 done
 End of test

3. Structured concurrency

Use globalscope When launching, a top-level collaboration will be created. It does not use the main thread. Although the newly created collaborative process is lightweight, it will still consume some memory resources. If you forget to keep the reference to the newly started collaboration, it will continue to run.

We can use structured concurrency in our code.

In the example, we use the runBlocking coroutine builder to convert the main function into a coroutine. There is no need to explicitly use join for the coprocessor started in the scope.

Observe the following example:

import kotlinx.coroutines.*
​
fun main() = runBlocking<Unit> {
 println("Main thread id ${Thread.currentThread().id}")
 launch { // Start a new procedure 1 in the runBlocking scope
 println("Thread of coroutine 1 id ${Thread.currentThread().id}")
 delay(300)
 println("Collaboration 1 completed")
 }
 launch { // Start a new process 2 in the runBlocking scope
 println("Thread of coroutine 2 id ${Thread.currentThread().id}")
 delay(500)
 println("Collaboration 2 completed")
 }
 println("Main thread execution completed")
}

Run log

Main thread id 1
 Main thread execution completed
 Thread of coroutine 1 id 1
 Thread of coroutine 2 id 1
 Collaboration 1 completed
 Collaboration 2 completed

As you can see, you don't need to call thread as before Sleep or delay makes the main thread wait for a period of time to prevent the virtual machine from exiting.

The program will wait until all its co processes are executed, and then really exit.

4. Scope builder

Declare your own scope using the coroutine scope builder. It creates a collaboration scope and waits for all started child collaborations to be executed.

runBlocking looks similar to coroutineScope because they both wait for the body of their coroutines and all their child coroutines to end. The main differences are:

  • The runBlocking method blocks the current thread to wait. It is a normal function
  • coroutineScope is only suspended. It will release the underlying thread for other purposes. It is a suspended function

The following example shows the characteristics of the scope builder. main is a scope.

import kotlinx.coroutines.*
​
fun main() = runBlocking { // this: CoroutineScope
 launch {
 delay(200L)
 println("Synergetic process 1 t${Thread.currentThread().id}")
 }
​
 coroutineScope { // Create a collaboration scope
 launch {
 delay(500L)
 println("Internal coordination process 2-1 t${Thread.currentThread().id}")
 }
​
 delay(100L)
 println("Synergetic process 2 t${Thread.currentThread().id}")
 }
​
 println("Main task completed")
}

Run log

Synergetic process 2 t1
 Synergetic process 1 t1
 Internal coordination process 2-1t1
 Main task completed

5. Extract function reconstruction

Extract the code block inside launch {...} into a separate function. The extracted function needs the suspend modifier, which is a suspended function.

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
​
fun main() = runBlocking<Unit> {
 launch { r1() }
 println("DONE")
}
​
// Suspend function
suspend fun r1() {
 delay(300)
 println("Extracted function")
}

log

DONE
 Extracted function

6. The coordination process is light

We have also tried to create a lot of collaborative processes before, and the program runs OK.

The following code can output many points

import kotlinx.coroutines.*
​
fun main() = runBlocking {
 for (t in 1..10000) {
 launch {
 delay(t * 500L)
 print(".")
 }
 }
}

7. The global process is like a daemon thread

If only the daemon thread is left in the process, the virtual opportunity exits. In the previous example, you can also see that the program ends before the characters are printed.

The active orchestration started in GlobalScope does not keep the process alive. They are like daemon threads.

Another example

import kotlinx.coroutines.*
​
fun main() = runBlocking {
 GlobalScope.launch {
 for (i in 1..1000000) {
 delay(200)
 println("Collaborative execution: $i")
 }
 }
​
 delay(1000)
 println("Bye~")
}

log

Collaborative execution: 1
 Collaborative execution: 2
 Collaborative execution: 3
 Collaborative execution: 4
Bye~

kotlin data sharing

Advanced Kotlin enhanced combat

140 episode Kotlin introduction to proficient in a full series of video tutorials (project development and actual combat)

Topics: Android kotlin