,它并不会造成函数阻塞,但是会挂起协程 协程作用域构建器 runBlocking 会阻塞当前线程,直到协程结束。...所以在实际应用中,我们更推荐 : 在执行操作所在指定作用域内启动协程,而非随意使用 协程的取消与超时 cancelAndJoin 取消一个协程并等待结束 runBlocking {...我们可以定义异步风格的函数来异步调用 playGame 和 playPP,并使用 async 协程建造器并带有一个显式的 GlobalScope引用 suspend fun main() {...当前所在线程----main @coroutine#1 当前所在线程----main @coroutine#2 lauch块+1 1 lauch块+2 lauch块+3 为什么 lauch依然运行呢?...协程中的取消操作总是通过抛出异常来执行,这样所有的资源管理函数(try{},finally{}块 会在取消的情况下正常运行 take 获取指定个数的发射个数,到达上限将停止发射 runBlocking
} println("Hello,") } 我们来将 launch { …… } 内部的代码块提取到独立的函数中。...当你对这段代码执行“提取函数”重构时,你会得到一个带有 suspend 修饰符的新函数。 这是你的第一个挂起函数。...任何尝试在 finally 块中调用挂起函数的行为都会抛出 CancellationException。...代码块中,而 withTimeoutOrNull 通过返回 null 来进行超时操作,从而替代抛出一个异常 fun main() = runBlocking { val result = withTimeoutOrNull...当调用 launch { …… } 时不传参数,它承袭了当前协程的上下文(以及调度器)。
它启动了一个新的协程作用域并且在所有子协程执行结束后并没有执行完毕。 ...// runBlocking 和 coroutineScope 主要的不同之处在于后者在等待所有的子协程执行完毕时并没有使当前线程阻塞 private fun testCoro() = runBlocking...finally中运行挂起函数就会抛异常 // print("i am running finally") //可以将相应的代码块包装在... print("now i can quit") } //用户关闭了协程界面,那么协程结束就没有必要了,它可以被取消 //协程取消是协作的...,这个协程是轻量级的,与其他协程一起并发工作,与launch启动协程不同,launch启动返回一个Job对象 // 不带有任何返回值,而async返回一个Defrred对象一个轻量级非阻塞future
image.png withContext kotlin 中 GlobalScope 类提供了几个创建协程的构造函数: launch: 创建协程 async : 创建带返回值的协程,返回的是 Deferred...类 withContext:不创建新的协程,指定协程上运行代码块 runBlocking:不是 GlobalScope 的 API,可以独立使用,区别是 runBlocking 里面的 delay 会阻塞线程...,而 launch 创建的不会 withContextt这个函数主要可以切换到指定的线程,并在闭包内的逻辑执行结束之后,自动把线程切回去继续执行: coroutineScope.launch(Dispatchers.Main
挂起后,它恢复线程中的协程,而这完全由被调用的挂起函数来决定。非受限的调度器非常适用于执行不消耗 CPU 时间的任务,以及不更新局限于特定线程的任何共享数据(如UI)的协程。...非受限的调度器是一种高级机制,可以在某些极端情况下提供帮助而不需要调度协程以便稍后执行或产生不希望的副作用, 因为某些操作必须立即在协程中执行。非受限调度器不应该在通常的代码中使用。...isActive println(s) } //输出 true 说明我当前的协程对象是活动的。 而为什么要添加“?” 那是因为对象可能为null。...() // 等待请求的完成,包括其所有子协程 println("所有的协程结束") } //输出 返回值:父协程本身已经执行完毕了,但我并没有调用方法明确的关闭所有子协程, 子协程的事务还没有结束...协程:0 结束 协程:1 结束 协程:2 结束 所有的协程结束 我们可以看到,父协程的代码已经执行完毕并输出了。
(3000L) //阻塞主线程防止过快退出 } println("\n示例结束") } 可以看到,runBlocking里使用了delay来延迟。...用了runBlocking的主线程会一直**阻塞**直到runBlocking内部的协程执行完毕。 也就是runBlocking{ delay }实现了阻塞的效果。...runBlocking 与 coroutineScope 看起来类似,因为它们都会等待其协程体以及所有子协程结束。...提取函数重构 将launch { …… }内部的代码块提取到独立的函数中。提取出来的函数需要 **suspend** 修饰符,它是**挂起函数**。...前文那个的例子,其实也能看到,字符没打印完程序就结束了。 在 **GlobalScope** 中启动的活动协程并不会使进程保活。它们就像守护线程。
当外部条件满足时,我们可以取消等待,并通过try-catch块来处理取消和异常。 2.2 使用isActive检查 在协程内部,你可以通过检查isActive属性来决定是否继续执行。...println("main: Now I can quit.") } 在这个示例中,我们在协程内部使用while (isActive)来检查协程是否被取消,并在取消时通过try-catch块来处理取消...如果协程被取消了,ensureActive会抛出CancellationException,并通过try-catch块来处理取消。...如果协程被取消了,yield会抛出CancellationException,并通过try-catch块来处理取消。...协程需要定期检查自己的取消状态,并在适当的时候退出。 3.2 误区2:取消协程会导致异常 取消协程不会抛出异常。如果协程没有正确处理取消状态,它可能会继续运行,直到自然结束或遇到其他错误。
isActive等于 false ,同时 isCompleted等于 true isCancelled 如果当前延迟任务被取消,返回true suspend fun await() 等待此延迟任务完成,而不阻塞线程...上下文的协程运行在主线程中; 继承了 runBlocking {...}...block.startCoroutine(this, this) } } 其中,参数说明如下: 参数名 说明 context 协程上下文 capacity 通道缓存容量大小 (默认没有缓存) block 协程代码块...它由两个主要包组成: kotlin.coroutines.experimental 带有主要类型与下述原语: createCoroutine() startCoroutine() suspendCoroutine...() kotlin.coroutines.experimental.intrinsics 带有甚至更底层的内在函数如 : suspendCoroutineOrReturn 大多数基于协程的应用程序级API
IO-Thread-1 的线程执行结束后才可以继续。...当数据库的事务操作都是在一个线程上完成的,这样的 API 不会有任何问题,但是使用协程之后问题就来了,因为协程是不绑定在任何特定的线程上的。...在事务开始时,Room 会获得 executor 中某个线程的控制权,直到事务结束。在事务执行期间,即使调度器因子协程发生了变化,已执行的数据库操作仍会被分配到该事务线程上。 ...然后 runBlocking 所创建的调度器会将要执行的代码块分发给已获得的线程。另外,Job 被用来挂起和保持线程的可用性,直到事务执行完成为止。...// 挂起 runBlocking 协程,直到 controlJob 完成。由于协程是空的,所以这将会阻止 runBlocking 立即结束。
函数原型如下 : /** * 在**流完成或取消后,返回一个调用给定[action] **的流 * 作为[action]原因参数的取消异常或失败。...* 并观察为取消流而抛出的异常。...[FlowCollector],这个操作符可以用来发出附加操作 * 元素在**结束,如果它成功完成**。...,任何发出额外元素的尝试都会引发相应的异常。...PID: 29378 SIG: 9 六、catch 代码块中捕获异常 ---- 上面章节中介绍了 在 Flow#onCompletion 中可以执行收尾 , 同时可以查看出现的异常 , 但是无法捕获处理异常
try…catch…finally 代码块 , 在 finally 代码块中的代码 , 即使是协程取消时 , 也会执行 ; 代码示例 : package kim.hsl.coroutine import...(1000) Log.i(TAG, "释放协程占用的资源完毕") } } 如果在协程取消后 , finally 代码块的代码肯定会执行 , 但是如果 finally 中 delay...挂起函数以及之后的代码将不会被执行 ; 使用 withContext(NonCancellable) {} 代码块 , 可以构造一个无法取消的协程任务 , 这样可以避免 finally 中的代码无法完全执行..., 但是整个代码块被 withContext(NonCancellable) 代码块包裹 , 所有的代码执行完毕 ; 23:12:31.014 I 协程任务执行开始 23:12:31.029 I...Log.i(TAG, "协程任务执行结束") // 执行完毕后的返回值 // 如果超时则返回 null
从前面我们可以大致了解了协程的玩法,如果一个协程中使用子协程,那么该协程会等待子协程执行结束后才真正退出,而达到这种效果的原因就是协程上下文,上下文贯穿了协程的生命周期,这套思想和我们app的上下文很像...,不能算是全新的协程 等等 3.子协程继承父协程时,除了Job会自动创建新的实例外,其他3项的不手动指定的话,都会自动继承父协程的,Job对应的是协程任务,每次新的任务肯定都是新的Job对象 有了这些概念后...,而是在根协程中直接使用子协程的方式,当然了,协程的上下文继承关系,使得我们的主协程等待子协程执行完毕后才结束生命 例子4: fun `test context life4`() = runBlocking...,使用了全新上下文的协程使用了async启动,哈哈,这就奇怪了,为什么会这样?...,同一继承关系下的协程使用await并无法捕获异常,还是会遵循第一条,导致整个协程生命周期结束 fun `test coroutineScope exception5`() = runBlocking
name} $it") } .launchIn(CoroutineScope(Dispatchers.IO)) .join()//主线程等待这个协程执行结束...之前我们调用子协程的取消时,CPU密集型代码并不能结束运行,在不使用挂起函数的情况下,我们在子协程体中通过ensureActive函数来检测该协程是否被取消了 1.而Flow为了方便,Flow构建器会对每个发射值...fun main() { runBlocking { val flow = flowOf(1, 2, 3, 5) .cancellable()//不指定,...3.有时我们不需要一个不漏的接收上流的元素时,可以使用conflate,下流来不及处理的会被丢弃掉 fun main() { runBlocking { val flow = flow...有时候我们需要在Flow完成时,做一些其他事情,可以使用下面的方式 1.finally块 fun main() { runBlocking { try{
为什么需要Flow 首先我们来回顾下Kotlin中我们如何使用挂起函数,我们在main方法中,调用挂起函数返回一组数据,代码如下所示: suspend fun loadData(): List...,我们可以看到 在main方法协程中,我们可以直接调用loadData的方法,这是因为flow构建块中的代码 就是一个suspend函数。...1 2 3 Process finished with exit code 0 我们会发现,如果我们没有调用flow的collect方法,其实不会进入flow的代码块中,也就是说 Flow中的代码直到被...flowOn Flow的代码块是执行在执行时的上下文中,比如 我们不能通过在flow中指定线程来运行Flow代码中的代码,如下所示: fun loadData1() = flow { withContext...那么我们如何指定Flow代码块中的上下文呢,我们需要使用flowOn操作符,我们将Flow代码块中的代码指定在IO线程中,代码如下所示: fun loadData1() = flow { for
这是为什么?...所以我们可以得出结论:运行 main () 函数的主线程, 必须要等到我们的协程完成之前结束 , 否则我们的程序在 打印Hello, 1和Hello, 2之前就直接结束掉了。...我们可以使用join, 让主线程一直等到当前协程执行完毕再结束, 例如下面的这段代码 fun testJoinCoroutine() = runBlocking {...因此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。...代码块中。
解答: launch和async都是用于启动新协程的构建器,但它们有以下不同点: launch:返回一个Job对象,用于表示协程的执行,不直接返回结果。...通常用于不返回结果的异步操作,如日志记录或执行后台任务。 async:返回一个Deferred对象,它也是Job的一种,但可以通过await()方法获取协程的结果。...面试题目2:描述Kotlin协程中的runBlocking构建器的作用及其潜在问题。 解答: runBlocking是一个协程构建器,它会立即启动协程并在当前线程阻塞,直到协程执行完成。...withContext接受一个新的上下文(如Dispatchers.IO)作为参数,并在该上下文中执行传递的代码块。当代码块执行完毕后,控制权会返回到原先的上下文中。...这两个函数允许你在指定的时间内执行一个协程块。如果在超时时间内协程块完成执行,withTimeout会抛出一个异常,而withTimeoutOrNull会返回null。
使用 flow: fun main() = runBlocking { launch { for (j in 1..5) { delay(100)...(火和冰形象地表示了 Hot、Cold Stream) migration from rxjava.jpeg 4.1 Cold Stream flow 的代码块只有调用 collected() 才开始运行...onCompleted() 功能,只有在正常结束时才会被调用: fun Flow.onCompleted(action: () -> Unit) = flow { collect...() -> Unit) = flow { collect { value -> emit(value) } action() } fun main() = runBlocking...} }.onCompleted { println("Completed...") } .collect{println(it)} } 但是假如 Flow 异常结束时
channel = Channel() launch { for (x in 1..5) channel.send(x * x) channel.close() // 我们结束发送...fun main() = runBlocking { val channel = Channel(4) // 启动带缓冲的通道 val sender = launch...协程内部使用 CancellationException 来进行取消,这个异常会被所有的处理者忽略,所以那些可以被 catch 代码块捕获的异常仅仅应该被用来作为额外调试信息的资源。...每个增量操作都得使用 withContext(counterContext) 块从多线程 Dispatchers.Default 上下文切换到单线程上下文。...3.互斥 该问题的互斥解决方案:使用永远不会同时执行的 关键代码块 来保护共享状态的所有修改。在阻塞的世界中,你通常会为此目的使用 synchronized 或者 ReentrantLock。
launch 是非阻塞的 而 runBlocking 是阻塞的。...多个 async 任务是并行的,async 返回的是一个Deferred,需要调用其await()方法获取结果 runBlocking一般用在测试中,会阻塞当前线程,会等到包裹的子协程都执行完毕才退出...LAZY:只有协程被需要时,包括主动调用协程的start、join或者await等函数时才会开始调度,如果调度前就被取消,那么该协程将直接进入异常结束状态 @Test fun `test start...,程序结束的时候会自动调用close方法,适合文件对象 //use函数在文件使用完毕后会自动调用close函数 BufferedReader(FileReader("xxx")).use { var...it") delay(500L) } } } 如果不想抛出异常,可以用withTimeoutOrNull /* * 超时任务,超时会返回null,不超时返回最后的
flow.collect {value -> println(value)} } Flow与其他方式的区别 名为flow的是Flow类型构建器函数 flow{...}构建块中的代码可以挂起 函数simpleFlow...(也可以用flowOn切换上下文来实现) conflate(),合并发射项,不对每个值进行处理,比如1-3,只处理1和3,中间的值不处理 collectLatest(),取消并重新发射最后一个值 当必须更改...zip操作符用于组合两个流中的相关值 2个流是异步的 @Test fun `test flow zip`() = runBlocking { val nums = (1..3).asFlow...当运算符中的发射器或代码抛出异常时,处理方法: try/catch块,捕获下游collect异常 catch函数(上游emit异常,可以在catch中恢复,比如补充数据) @Test fun `test...当流收集完成时(普通情况或异常情况),它可能需要执行一个动作 命令式finally块 onCompletion声明式处理,onCompletion还能拿到异常信息,但是不能捕获异常,同时能获取上游异常信息和下游异常信息
领取专属 10元无门槛券
手把手带您无忧上云