Kotlin 协程(2) Basics


I. Open exemplary coroutine

 //全局式. 协程的生命周期只受整个应用程序的生命周期的限制。
 GlobalScope.launch(Dispatchers.Unconfined) {
     println("hello, (${Thread.currentThread().name})")
     delay(1000L)
     println("stone")
 }
 // GlobalScope.async { }

//阻塞式
runBlocking {
    delay(1000L) //与上一个delay基本是同时执行的,只晚一点点。
    println("Did you win the lottery?")
}

//阻塞式 返回 T
val v = runBlocking {
    delay(1500L)
    GlobalScope.launch {
        println("yeah. $2")
    }
    delay(500)
    "i win"
}
println(v)

i. launch()is the CoroutineScopeextension function

See the source code,

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}

We will build an internal coroutineinstance and calls start()to start the coroutine. Return Jobinstance.

ii. async()also CoroutineScopeextended function

We will build an internal coroutineinstance and calls start()to start the coroutine. Return Deferredinstance.
Look at the function name is asynchronous meaning, but it does not mean necessarily run in asynchronous thread. But its function may not be executed immediately.

iii. runBlocking()is a function

@Throws(InterruptedException::class)
public fun <T> runBlocking(context: CoroutineContext = EmptyCoroutineContext, block: suspend CoroutineScope.() -> T): T {
    val currentThread = Thread.currentThread()
    val contextInterceptor = context[ContinuationInterceptor]
    val eventLoop: EventLoop?
    val newContext: CoroutineContext
    if (contextInterceptor == null) {
        // create or use private event loop if no dispatcher is specified
        eventLoop = ThreadLocalEventLoop.eventLoop
        newContext = GlobalScope.newCoroutineContext(context + eventLoop)
    } else {
        // See if context's interceptor is an event loop that we shall use (to support TestContext)
        // or take an existing thread-local event loop if present to avoid blocking it (but don't create one)
        eventLoop = (contextInterceptor as? EventLoop)?.takeIf { it.shouldBeProcessedFromContext() }
            ?: ThreadLocalEventLoop.currentOrNull()
        newContext = GlobalScope.newCoroutineContext(context)
    }
    val coroutine = BlockingCoroutine<T>(newContext, currentThread, eventLoop)
    coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
    return coroutine.joinBlocking()
}

We will build an internal coroutineinstance and calls start()to start the coroutine. The return value is passed block()in the last line. Therefore, the sample code will be output i win.
This blocking is achieved, i.e., will be understood to be synchronous, asynchronous non-implementation. The caller is blocking the thread.

Console program, if used in a non-blocking delay coroutine () may be the main function main () has finished execution, subsequent operations can not be seen. So, can the main (), declared as:fun main() = runBlocking { ... }


II. Kotlinx coroutine library CoroutineScopegenealogy

i. Genealogy

CoroutineScope family tree
The figure is based coroutine library kotlin.coroutines 1.3.5 (non Andrews on) the CoroutineScopegenealogy.

public interface CoroutineScope {
    public val coroutineContext: CoroutineContext
}

See the source code CoroutineScopedefined inside the definition of a constant coroutineContext, in fact it is abstract. As a custom CoroutineScope:

class MyContextScope(override val coroutineContext: CoroutineContext) : CoroutineScope {

}

FIG binding, it is understood, to achieve these internal sdk XxxCoroutinecoroutine, in fact achieved CoroutineScope.
They will coroutineContext assignment process.

ii. suspend function coroutineScope()

public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R =
    suspendCoroutineUninterceptedOrReturn { uCont ->
        val coroutine = ScopeCoroutine(uCont.context, uCont)
        coroutine.startUndispatchedOrReturn(coroutine, block)
    }

The sdk function, is a function pending, creates an internal coroutinecoroutine example.
Its function is suspended, it must be substituted with one or another coroutine suspend function call.

fun main(args: Array<String>) = runBlocking {
	coroutineScope {
        launch {
            delay(500L)
            println("Task from nested launch")
        }
        delay(100L)
        println("Task from coroutine scope") // This line will be printed before the nested launch
    }
}

III. JobDeferred

i. JobIntroduction

launch()Return Job, which implements CoroutineContextan interface; interior has three attributes:

public val isActive: Boolean
public val isCompleted: Boolean
public val isCancelled: Boolean

Documentation comment, there is a simple schematic flow diagram below, the effect of three properties described above:

                                    wait children
+-----+ start  +--------+ complete   +-------------+  finish  +-----------+
| New | -----> | Active | ---------> | Completing  | -------> | Completed |
+-----+        +--------+            +-------------+          +-----------+
               |  cancel / fail       |
               |     +----------------+
               |     |
               V     V
           +------------+                           finish  +-----------+
           | Cancelling | --------------------------------> | Cancelled |
           +------------+                                   +-----------+

New Job instance, starts to enter the Active state;
Active state, you can cancel, canceled after completion, enter Cancelled status;
Active state, the normal completion of the execution (if there are sub-Job, wait for all children Job perform complete ), enter the completed state; if not complete itself or sub-Job execution was canceled or an error occurs, enter Cancelled state.

. ii Jobimportant cancel()functions: join(), ,cancelAndJoin

For example a

val job = GlobalScope.launch {
   delay(1000L)
   launch {
       delay(8000)
       println(8/0)
   }
    println("World!")
}
job.cancel()
println("Hello,")
//    job.join() // wait until child coroutine completes
println("unprecedented ${job.isCompleted}")
println("unprecedented ${job.isCancelled}")

cancel()Cancel Job, in fact, canceled the GlobalScope.launch{}entire coroutine task. (Delay (1000) before other codes will still be executed.) job.isCompleted 值是 false,job.isCancelled 值是 true

Open job.join()after job.isCompleted 值是 truecomments job.isCancelled 值是 true, . join()Is waiting for all the children are finished, so later, it's isCompleted 是 true.

cancelAndJoin()Internal implementation is called first cancel()and then calljoin()

For cancel () is not a call will be immediately canceled. It will co-drive in the face of "suspended" operation, in order to successfully canceled.

iii. Jobsubclass Deferred
async()return Deferred. It is one more important way await().

 // 挂起函数中,调用其它挂起函数;挂起协程
suspend fun doWorld() {
    delay(1000L)
    println("World!")
    repeat(10) { i ->
        print("${i}\t")
    }
    println()
}
//协程中 调用挂起函数
val deferred1 = async {
    doWorld()
    "done ${Thread.currentThread().name}"
}
println(deferred1.await())

val deferred2 = async(start = CoroutineStart.LAZY) {
    println("时间:${System.currentTimeMillis()}")
    "done ${Thread.currentThread().name}"
}
delay(3000)
println(deferred2.await())

async()The default will be executed immediately, such as val r = async {...}; call deferred1.await()can get the results.
val deferred2 = async(start = CoroutineStart.LAZY) {...}When the start is Lazy, coroutine call will deferred2.await()begin when.


IV. Summary

How to open a coroutine:

GlobalScope global, internal thread pool, optional launch (), async ()
non-global, and is not associated with the specified asynchronous thread CoroutineContext parameter, the default is to perform in the caller's thread.
launch () returns Job, async () returns Deferred. The return value whether operation selection.
runBlocking () blocks the caller thread Note that it requires a return value, even empty type of Unit.
Suspend function coroutineScope () to create a non-global co-away.


V. References

Basics coroutines
Kotlin coroutine library


Published 400 original articles · won praise 364 · Views 1.62 million +

Guess you like

Origin blog.csdn.net/jjwwmlp456/article/details/105194794