绍兴企业自助建站网站建设上海网站建设
2026/4/15 11:03:53 网站建设 项目流程
绍兴企业自助建站,网站建设上海网站建设,织梦网站做自动生成地图,建筑公司注册条件种一颗树的最好时机是十年前#xff0c;其次是现在。 学习也一样。 跟着霍老师的《深入理解 Kotlin 携程》学习一下协程。 一点前言 随着RxJava的流行#xff0c;响应式编程模型逐步深入人心。Flow就是kotlin协程与响应式编程模型结合的产物。 认识Flow 我们从序列生成器开始…种一颗树的最好时机是十年前其次是现在。学习也一样。跟着霍老师的《深入理解 Kotlin 携程》学习一下协程。一点前言随着RxJava的流行响应式编程模型逐步深入人心。Flow就是kotlin协程与响应式编程模型结合的产物。认识Flow我们从序列生成器开始valintssequence{(10..30).forEach{yield(it)}}这里如果希望在元素之间加个延时怎么办因为受restrictsSuspension注解的约束delay函数不能再SequenceScope的扩展成员中被调用假设序列生成器不受这个限制调用delay函数会导致后续的执行流程的线程发生变化外部的调用者发现在访问ints的下一个元素的时候居然还会有切换线程的副作用。不仅如此通过制定调度器来限定序列创建所在的线程同样是不可以的我们甚至没有办法为它设置协程上下文。那么我们来看一下Flow。valintFlowflow{(1..3).forEach{emit(it)delay(1000)}}Flow也可以设定它运行时所使用的调度器intFlow.flowOn(Dispatchers.IO).collect{println(it)}最终消费intFlow需要调用collect函数。冷数据流在Flow创建出来之后不消费则不生产多次消费则多次生产生产和消费总是相对应的。suspendfunmain(){valintFlowflow{(1..3).forEach{emit(it)delay(1000)}}intFlow.flowOn(Dispatchers.IO).collect{println(it)}intFlow.flowOn(Dispatchers.IO).collect{println(it)}}这里会输出两次“123”异常处理Flow的异常处理也比较直接直接调用catch函数即可。需要注意的是catch函数只能捕获它上游的异常并且当我们没有调用catch函数时未捕获的异常会在消费时抛出。当然了我们可以使用onCompletion来进行FLow完成时的逻辑suspendfunmain(){flow{emit(1)throwArithmeticException(div 0)}.catch{t:Throwable-println(caught error :$t)}.onCompletion{t:Throwable?-println(finally.)}.flowOn(Dispatchers.Default).collect{value-println(value)}}onCompletion类似于try ... catch ... finally中的finally。这套处理机制的设计初衷是确保Flow操作中异常的透明因此我们不能或者禁止这样写flow{try{emit(1)throwArithmeticException(Div 0)}catch(e:ArithmeticException){println(caught error:$e)}finally{println(finally)}}末端操作符collect是最基本的末端操作符还有其他末端操作符大体分为两类集合类型转换操作符包括toList、toSet等聚合操作符包括将Flow规约到单值的reduce、fold等操作还有获得单个元素的操作符包括single、singleOrNull、first等由于Flow的消费端一定需要运行在协程中因此末端操作符都是挂起函数。分离Flow的消费和触发我们还可以通过onEach来做到这一点这样消费的具体操作就不需要与末端操作符放到一起collect函数可以放到其他任意位置调用funcreateFlow()flowInt{(1..10).forEach{emit(it)delay(1000)}}.onEach{println(it)}suspendfunmain(){GlobalScope.launch{createFlow().collect()}delay(20*1000)}需要注意一下Flow并没有提供取消操作想要取消Flow只需要取消它所在的协程即可。其他Flow的创建方式当我们使用flow{...}来创建Flow时无法随意切换调度器因为emit函数不是线程安全的。想要在生成元素时切换调度器就必须使用channelFlow函数来创建FlowchannelFlow{send(1)withContext(Dispatchers.IO){send(2)}}此外我们可以通过集合矿建来创建Flowsuspendfunmain(){listOf(1,2,3,4).asFlow().collect{value-println(value)}setOf(1,2,3,4).asFlow().collect{value-println(value)}flowOf(1,2,3,4).collect{value-println(value)}}背压只要是响应式编程就一定会有背压问题背压问题在生产者的生产速率高于消费者的处理速率情况下出现。为了保证数据不丢失我们可以添加一个制定容量的buffer。但这只是治标不治本的方法随着时间的推移还是会造成时间上的积压。出现背压问题的根本原因是生产者和消费者的速速率不匹配除了直接优化消费者的性能外我们还可以采取一些取舍的手段。第一种是conflate和Channel的Conflate模式一致新数据覆盖老数据。suspendfunmain(){flow{List(100){emit(it)}}.conflate().collect{value-println(Collected:$value)delay(100)println($valuecollected)}}虽然我们发送了100个元素但最终只接收到2个多次运行的结果并不相同。第二种是collectLasted只处理最新的数据区别在于collectLasted并不会直接用新数据覆盖老数据而是每一个数据都会处理只不过如果前一个还没被处理完后一个就来了话处理前一个数据的逻辑就会被取消。suspendfunmain(){flow{List(10){emit(it)}}.collectLatest{value-println(Collected:$value)delay(1000)println($valuecollected)}}输出Collected: 0Collected: 1Collected: 2Collected: 3Collected: 4Collected: 5Collected: 6Collected: 7Collected: 8Collected: 99 collected前面的println(Collected: $value)输出了所有结果后面的println($value collected)只输出了最后一个结果因为后面的数据到达时处理上个数据的操作正好被挂起了。除此之外还有mapLatest,flatMapLatest等。Flow的变换我们可以使用map来变换Flow的数据suspendfunmain(){flow{List(5){emit(it)}}.map{it*2}.collect{println(it)}}输出02468还有按照顺序拼接的flattenConcat不保证顺序的flattenMerge操作等以上

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询