版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
作者pengrbKotlin协程指南目录桥接阻塞和非阻塞从本质上来说,协程是属于轻量级线程,被协程构建器所启动,可以用launch(CommonPool){...}替换thread{...}和delay(...)替代Thread.sleep()从而获取相同效果如果使用thread来替换launch(CommonPool)那是因为delay是一个特殊的挂起函数,它不会阻塞一个线程,而是暂停协程(Coroutine)桥接阻塞和第一个例子在main方法中混合了非阻塞的delay()和阻塞的Thread.sleep(),那样有点混乱,可以使用运行结果一样,但这段代码只使用于非阻塞的delay,而runBlocking{}被作为一个顶层的主协程的适配器,运行其实runBlocking{}是用来阻塞当前线程而运行新的协程(coroutine),直到该协程执行完,runBlocking不应该被用在协程(coroutine)为了将常规线程的阻塞代码连接到协程暂停而编写的库,一般主要用于main方法或者测试用例为suspending使用延时来让另一个协程执行任务不是一个好的方式,可以使用job.join()将launch(CommonPool){}中的代码块提取到一个单独的函数中,当对此代码执行"Extractfunction"重构时,可以获取一个带有suspend修饰符的新函数,他是一个延时函数,suspend函数可以类型普通函数一样在协程Coroutine中被调用,而且它还可以使用其他协程的延时函数,比如delay()函数暂停执行一个协程Coroutine它启动100k协程,1以下代码启动一个长时间运行的协程,每秒打印一次“我正在睡觉”,然后延迟一段时间后返回main在小应用中,一般主要从main方法的返回可以让所有的协程Coroutine需要更细微的控制,使用launch函数返回一个可以用来取消运行的协程(Coroutine)的任务:协程取消是合作性的,协程代码必须通过合作才能取消,在kotlinx.coroutines协程调用取消时会检查任务取消并抛出取消异常(CancellationException),任务取消,则不能被调用取消,例如下面例子:可以很明显看出,该协程被调用job.cancel()取消后还在继续打印I'm有两种协程取消方法:定期调用一个挂起函数yield用while(isActive)替换前一个例子中的while(True)可以看到这个循环可以被取消了,isActive是定义在协程中CoroutineScopeisActive返回true时,表示协程处于活跃状态,CoroutineScope接口用于通用协程构建器的接收接口,以便协程中可取消挂起的函数在取消时抛出CancellationException,可以使用try{}finally{}在上一个示例的finally块中使用挂起函数将会导致CancellationException,因为运行的协程被取消了,通常这并的,不涉及任何挂起的功能,但是在特殊情况下,当你需要在取消协程中使用挂起时,可以run方法和NonCancellable上下文来包装相应的代码run(NonCancellable){...},比如下面的例子:withTimeout()来执行,例如:从运行结果可以看出,使用withTimeout()TimeoutException是CancellationException的一个私有子类,还没看到它的堆栈跟踪打印在控制台上,这是因为在一个被取消协程中CancellationException被认为是一个协程正常的执行完成导致的,然而在这个例子中,在main方法中使用了withTimeout()因为取消操作是一个会抛出异常,通常会伴随关闭资源操作,可以使用try{withTimeout(){...}}catch(e:CancellationException){}来处理withTimeout()挂起函数(Suspend)行如果需要依次调用他们,该怎么做?首先调用doSomethingUsefulOne(),然后调用doSomethingUsefulTwo()的总和?实际中如果我们使用第一个函数的结果来决定是否需要调用第二个函数或者决定如何它,那么就这样做。所需的总时间来说明这一点:如果想要同时执行doSomethingUsefulOne()和doSomethingUsefulTwo(),需要使用async从概念上来说,async就像launch一样,可以启动一个单独的协程,他是一个轻量级线程,与所有其他协程同时执行,不同的是,launch返回一个任务并且不任何结果值,而async返回一个Deferred(轻量级非阻塞的Future用来保),.await()获取返回的结果,因为Deferred也是任务,所以可以被取消可以发现,使用async同时处理两个协程的速度比起上面的例子可以快2在async中有一个懒加载的选项CoroutineStart.LAYZ参数,该参数表示需要等待await或者启动函数时被调用,可以看出通过使用懒加载Lazy参数,async等待执行两个任务不是懒加载的预期用例,而在求和及挂起挂起功能的前提下,它只是被设计成替代标准懒加载罢了我们可以用异步的协程构建器来定义异步样式的函数doSomethingUsefulOne()和doSomethingUsefulTwo(),异步样式函数一般会以"async"为前缀或者"Async"为后缀标识函数名,例如:注意:这些asyncXXX函数不是挂起函数,可以在任何地方(协程外)使用,然而这些函使用总是意味着协程异步执行他们所调用的代码,例如下面的例子,可以看到他们在协程外使用:协程上下文(Context)及协程调度器在launch(CommonPool){...},async(CommonPool){...},run(NonCancellable){...}这些中可以看到NonCancellable是协程的上下文协程上下文包括一个协程调度器(coroutinedispatcher),它决定了应协程被执行一个线程或多个线程中,协程调度器(coroutinedispatcher)非限制的(Unconfined)协程调度器(Coroutinedispatcher)开启协程(coroutine)只有在第一个挂起点(suspensionpoint)时被线程调用,在线程中暂停之后重新启用,完全取决于被调用的挂起函数。非限制协程调度适用于协程(coroutine)不消耗CPU时间片,也不更新任何被限制在特定线程的共享数据(如UI)。CoroutineScope接口可以在任何协程块中提供上下文(Context)属性协程Context的引用,通过这种方式,可以继承父级上下文(parentcontext),特别是runBlocking默认的Context被限制为调用的线程,所以继承FIFO(先进先出)调度的线程上的效果,即runBlocking默认的Context限制其所在的main行因此,协程继承了 }的上下文,继续在主线程中执行,而非限制的协程在使用delay()函数的调协程可以在一个线程上挂起并且在另一个线程上使用Unconfined调度程序或者像CommonPool这样的多线程调度中恢复,即使是单线程的调度程序,也很难弄清楚协程在做什么,在什么地方,在什么时候做什么。使用线程调试见方法是在每个日志语句的日志文件中打印线程名,日志记录框架通常支持此功能。当使用协程时,单独的线程名不会给出很多上下文,因此Kotlinx.coroutines有调试工具,使调试更容易。设置debug使用- JVM调试选项运行下面代码式时,这个标识符被连续的分配给所有创建的协程你可以在newCoroutineContext设置debug使用-Dkotlinx.coroutines.debugJVM这里使用了两种技术:一种是使用带有显式指定Context,另一种是使用run持在相同的协程作用下协程的任务(Job)是协程上下文的一部分,协程可以从context[Job]表达式中获取协程的因此,CoroutineScope中的isActive只是一个方便的context[Job]!!.isActive当协程的上下文被用来启动另一个协程时,新协程的任务(Job)成为父协程的任务(Job)时,其所有子协程也会被递归取消使用“+”操作符可以组合使用协程的上下文,右边的Context替换了左边的Context被替换时,父类的Job只需要将相同协程工作的日志相关联即可在协程日志记录中自动分配id,CoroutineName与线程名具有相同功能,当打开调试更多时,它将显示在正在执行此协程的线程名称中。使用-Dkotlinx.coroutines.debugJVM让我们把关于Context、子协程和Job例如android程序,并在Android的activity的Context中启动各种协程用以执行异步操作来获取和更新数据,执行动画等等,当activity被销毁时为了避免内存泄漏,必须取消这些协程可以通过创建一个与activity声明周期相关联的Job实例来管理我们的协程的生命周期,使用Job()工厂函数创建Job例,如下例子所示,需要确保所有的协程都是在其上下文开启任务,然后单次调用Job.canceljob.cancel()取消协程。所以在假设的Android应用程序中需要做的是在创建activity时创建一个父级Job对象,将其用于子协程并在activity消。通道延迟值(DeferredValue)提供一种可以在协程之间传输单个值的方便方法,通道(Channel)方法。一个通道(Channel)在概念上非常类似于BlockingQueue,一个关键区别是,通道不是阻塞的put操作,而是有一个挂起发送(suspendingsend)take操作,而是有一个挂起接收(suspendingreceive)。与队列不同,通道可以close()操作,表示不再处理更多进入通道的元素,接收者可以使用for循环close()所有之前发送的元素都被接收到构建通道生产者(Channel以channel作为参数的函数返回结果必须是函数。下面是一个名为produce的协程构建器来方便提供生产者,而其扩展函数consumeEach{...}可以替代消费者的for循环。管道是一种模式,是一个协程产生的无限数据流(发送端),另一个协程或多个协程在消耗数据流(接收端),数字求平方:连接整个管道停止管道,或者可以使用一个管道协程作为子协程处理以极端的管道为例,使用管道的协程生成素数,从数字序列开始,这次介绍一个明确的Context制协程运行的位置:下面的Pipeline下面例子输出了前10个素数,在主线程的Context运行整合的注意:你可以使用标准库中的buildIterator协程构建相同的管道,使用buildlterator替换produce,用yield替换send,用next替换receive,用Iterator替换ReceiveChannel,和不用Context,也将不需要runBlocking,但是如上所示使用channel中的Pipeline的好处是:如果在CommonPool中运行协程,可以使用CPU多内核处理。无论如何,这是一个非常不切实际的方式来找到素数,实际上,Pipeline确实涉及一些其他挂起的调用(远程服务)。并且这些Pipeline不能使用buildSeqeunce/buildIteractor构建,因为它们不允许任意挂起,而produce。多个协程之间可以从同一个channel中分配接收数据,让我们从一个定期产生整数的生产者协程开始(每秒10个数字现在开启5注意:取消一个生产者协程会关闭它的channel,从而最终终止处理的协程正在执行的channel的迭代多输入(Fan-in多个协程可以发送到同一个channel中,例如有一个字符串的channel,以及一个挂起函数,它通过指定的delay字符串发送到该channel中缓存通道(BufferedChannel()produce构建器都可以使用一个可选的缓存参数capacity(默认是capacity=0)来指定缓冲区大小,缓冲区允许发送者在挂起之前发送多个元素,类似于具有指定容量的阻塞队列(BlockingQueue),直到缓冲区满后再阻塞前4个元素被添加到缓冲区中,当发送第5个元素时,channel.send()Channel的Send操作和Receive程“ping”和协程“pong”从共享的“table”channel接收“ball对象”:“ping”协程首先启动,所以它是第一个接收球的,即使“ping”协程在将球send回table被“pong”协程接收,因为它已经在等待了可以使用CommonPool同步,协程在这个问题的解决方案与多线程的解决方案相似,但是其他解决方案是唯一的。让我们启动一千个协程执行一千个同样的任务(共执行一百万次),使用多线程的CommonPool从结果可以看出Counter=1000000注意:如果你有一个2个或更少的单任务老CPU系统,那么将始终看到1000000,因为这种情况下,CommonPool程中运行,要重现问题,需要进行以下更改使用2个线程上下文执行协程当使用1个线程上下文执行协程@Volatile有一个常见的误解是:使用@Volatile这段代码运行速度很慢,但是最终还是没有得到Counter=1000000,因为volatile变量保证线性化(这是“原子”的线程安全的数据结构(AtomicInteget适用于线程和协程的通用解决方案是使用线程安全(也称为同步,线性化或原子)incrementAndGet操作的AtomicInteget类:容易扩展到复杂状态或不具有即用型线程安全实现的复杂操作线程限制是共享可变状态问题的一种方法,其中对特定共享状态的所有访问都限于单个线程,它通常用于UI其中所有UI状态都限于单个事件分发/应用程序线程,使用协程很容易使用单线程上下文:这段代码运行非常慢,因为它执行细粒度的线程限制,每个单独的增量使用run(){...}从多线程CommonPool上下文切换到单线程上下文。首先在单线程上下文中运行每一个协程:synchronizedReentrantLockMutex(互斥)lock()unlock()功能来分隔临界区,关键的区别是Mutex.lock()是一个挂起函数而不会阻塞线程。这个例子中的锁是细粒度的,因此会付出代价(耗时),不错的选择,但该状态并不存在自然线程。一个actor是一个协程的组合,是被限制并封装到这个协程状态,以及一个与其他协程通信的通道(channel)单的actor可以写成一个函数,但是具有复杂状态的actor更适合作为一个类。这里有一个actor协程构建器,它方便将actor的mailboxchannel合并到它的作用域来接收消息,并将sendchannel合并无论actor的上下文是如何执行的都不重要,actor解决共享可变状态问题的解决方案。在负载下Actor注意:一个actor协程构建器是一个产生coroutinebuilder的双重角色,一个actor与它接收消息的channel相关联,select表达式(select<R>{...channel中select表达式两个String生产者:“fizz”和“buzz”,fizz每300ms产生“fizz”和buzz每500ms产生
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年武汉铁路桥梁职业学院单招职业技能测试题库及完整答案详解1套
- 2026年梅河口康美职业技术学院单招职业倾向性考试题库及答案详解一套
- 2026年湖南电子科技职业学院单招职业倾向性考试题库及完整答案详解1套
- 2026年江苏食品药品职业技术学院单招职业倾向性考试题库及答案详解1套
- 教师清贫面试题及答案
- 装修公司与施工方安全施工协议书范本
- 2025年中国移动通信嵊泗分公司招聘备考题库有答案详解
- 2025年中共西藏自治区委员会党校(西藏自治区行政学院)急需紧缺人才引进备考题库及参考答案详解1套
- 2025年山西华冶勘测工程技术有限公司公开招聘检测专业人才的备考题库及一套完整答案详解
- 2025年中国科学院上海药物研究所许叶春课题组科研助理招聘备考题库及参考答案详解
- 风电场冬季安全培训课件
- 2025年江苏烟草笔试试题及答案
- 2025年武汉东西湖分局招聘警务辅助人员招聘73人考试参考试题及答案解析
- DB32-T 5181-2025 装配式混凝土结构减震隔震技术规程
- 安全培训发酵车间环境课件
- (2025年)有限空间作业安全培训考试试题(+答案)
- QGDW11221-2023低压综合配电箱技术规范(参考文本)
- 铜精矿外贸采购合同范本
- 中原银行笔试题及答案
- 兽医心脏超声培训课件
- 学堂在线 雨课堂 学堂云 中国传统艺术-篆刻、书法、水墨画体验与欣赏 章节测试答案
评论
0/150
提交评论