Article Directory
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 CoroutineScope
extension 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 coroutine
instance and calls start()
to start the coroutine. Return Job
instance.
ii. async()
also CoroutineScope
extended function
We will build an internal coroutine
instance and calls start()
to start the coroutine. Return Deferred
instance.
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 coroutine
instance 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 CoroutineScope
genealogy
i. Genealogy
The figure is based coroutine library kotlin.coroutines 1.3.5 (non Andrews on) the CoroutineScope
genealogy.
public interface CoroutineScope {
public val coroutineContext: CoroutineContext
}
See the source code CoroutineScope
defined 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
XxxCoroutine
coroutine, in fact achievedCoroutineScope
.
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 coroutine
coroutine 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. Job
、Deferred
i. Job
Introduction
launch()
Return Job
, which implements CoroutineContext
an 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 Job
important 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 值是 true
comments 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. Job
subclass 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