当前位置: 首页 > wzjs >正文

网站镜像 动态搜索引擎优化seo名词解释

网站镜像 动态,搜索引擎优化seo名词解释,简单网站建设,福州做网站建设公司一、挂起函数源码分析1.编译器转换(CPS 转换)挂起函数,只是比普通的函数多了suspend关键字。有了这个suspend关键字以后,Kotlin编译器就会特殊对待这个函数,将其转换成一个带有Callback的函数,这里的Callba…

一、挂起函数源码分析

1.编译器转换(CPS 转换)

        挂起函数,只是比普通的函数多了suspend关键字。有了这个suspend关键字以后,Kotlin编译器就会特殊对待这个函数,将其转换成一个带有Callback的函数,这里的Callback就是Continuation接口。而这个过程,我们称之为CPS转换
suspend fun fetchData(url: String): String {delay(1000) // 挂起点1val result = api.request(url) // 挂起点2return result
}//编译器会将其转换为带有 Continuation 参数的普通函数,函数签名变为:fun fetchData(url: String, continuation: Continuation<String>): Any?
  • 新增的Continuation<String>参数:本质是一个 “回调对象”,保存了挂起函数暂停时的执行状态(如局部变量、程序计数器、调用栈信息等),用于后续恢复执行。
  • 参数返回值变为Any?:有两种可能结果:
    1. 若函数正常执行完成(未挂起),返回实际结果(如String);
    2. 若函数需要挂起,返回一个特殊标记COROUTINE_SUSPENDED,告知调用者 “当前函数已挂起,需等待后续恢复”。

Continuation是挂起函数状态保存与恢复的核心接口,源码定义简化如下:

interface Continuation<in T> {val context: CoroutineContext // 协程上下文(含调度器等信息)fun resumeWith(result: Result<T>) // 恢复执行的触发方法
}
  • context:保存协程的调度器(Dispatcher)、Job 等信息,决定恢复执行时使用哪个线程。
  • resumeWith:当挂起条件满足(如delay时间到、网络请求返回)时,通过此方法触发挂起函数的恢复,result为挂起期间的执行结果(成功或异常)。

2.状态机实现

        当挂起函数经过反编译以后,它会变成由switch和label组成的状态机结构编译器会生成一个状态枚举(如State),每个状态对应一个挂起点前后的逻辑:
private enum class FetchDataState {INITIAL, // 初始状态(未执行)AFTER_DELAY, // 执行完delay后的状态AFTER_REQUEST // 执行完api.request后的状态
}

同时,函数会被改造为一个状态机处理函数,大致逻辑如下:

fun fetchData(url: String, continuation: Continuation<String>): Any? {// 从continuation中获取或初始化状态机val stateMachine = continuation as? FetchDataStateMachine ?: FetchDataStateMachine(continuation)val context = continuation.contextreturn when (stateMachine.state) {FetchDataState.INITIAL -> {// 第一次执行:处理初始逻辑,调用第一个挂起函数(delay)stateMachine.url = url // 保存局部变量stateMachine.state = FetchDataState.AFTER_DELAY // 更新状态// 调用delay,将当前状态机作为其continuation传递val delayResult = delay(1000, stateMachine)if (delayResult == COROUTINE_SUSPENDED) {return COROUTINE_SUSPENDED // 触发挂起} else {// 若delay未挂起(如时间为0),直接进入下一个状态stateMachine.state = FetchDataState.AFTER_DELAY// 继续执行下一段逻辑(相当于“伪恢复”)fetchData(url, stateMachine)}}FetchDataState.AFTER_DELAY -> {// 从delay恢复后:执行第二个挂起函数(api.request)stateMachine.state = FetchDataState.AFTER_REQUESTval requestResult = api.request(stateMachine.url, stateMachine) // 传递状态机if (requestResult == COROUTINE_SUSPENDED) {return COROUTINE_SUSPENDED // 再次挂起} else {// 若request未挂起,直接进入下一个状态stateMachine.state = FetchDataState.AFTER_REQUESTfetchData(url, stateMachine)}}FetchDataState.AFTER_REQUEST -> {// 从api.request恢复后:返回结果val result = stateMachine.result // 从状态机中取出request的结果stateMachine.continuation.resumeWith(Result.success(result)) // 通知上层恢复null // 执行结束}}
}// 状态机类:保存局部变量和当前状态
private class FetchDataStateMachine(val continuation: Continuation<String>
) : Continuation<String> by continuation {var state: FetchDataState = FetchDataState.INITIALvar url: String = "" // 保存局部变量urlvar result: String = "" // 保存api.request的结果
}
        协程状态机代码:其中,when
表达式实现了协程状态机,而continuation.label 则代表了当前状态机的具体状态,continuation.label 改变一次,就代表了挂起函数被调用了一次;

3.挂起函数触发后的挂起和恢复流程

  1. 编译转换:挂起函数被转换为带Continuation参数的函数,逻辑拆分为状态机。
  2. 初始执行:从INITIAL状态开始,执行到第一个挂起点(如delay)。
  3. 挂起触发:若挂起函数返回COROUTINE_SUSPENDED,当前函数返回该标记,线程释放。
  4. 等待恢复:挂起期间,Continuation(状态机)被保存,等待条件满足(如时间到)。
  5. 恢复执行:条件满足后,Continuation.resumeWith被调用,状态机从上次保存的状态(如AFTER_DELAY)继续执行。
  6. 执行完成:当所有状态执行完毕,通过最上层的Continuation返回结果,整个挂起函数执行结束。

阶段总结

        挂起函数因带有suspend关键字会被 Kotlin 编译器进行 CPS 转换,即转换为带有Continuation参数的普通函数,Continuation作为回调对象保存挂起时的执行状态(如局部变量、调用栈等),函数返回值变为Any?,要么是实际结果,要么是特殊标记COROUTINE_SUSPENDED表示挂起;

        转换后的函数会形成由switchlabel组成的状态机结构,编译器生成对应挂起点的状态枚举,状态机通过when表达式实现状态流转,状态机类保存局部变量和当前状态,每次状态改变代表挂起函数被调用一次;

        其挂起和恢复流程为:编译转换后从INITIAL状态开始执行,到挂起点时若返回COROUTINE_SUSPENDED则触发挂起并释放线程,挂起期间Continuation保存状态等待条件满足,条件满足后通过Continuation.resumeWith恢复执行,状态机从上次保存的状态继续,直至所有状态执行完毕,通过最上层Continuation返回结果。

二、lauch的启动源码分析

        底层都依赖着协程构建器(Coroutine Builder)协程上下文(CoroutineContext)

1.协程启动的入口函数:CoroutionScope.launch

launchCoroutineScope的扩展函数,用于启动一个不返回结果的协程。其源码定义如下:

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)elseStandaloneCoroutine(newContext, active = true)// 根据启动模式决定是立即执行还是延迟执行coroutine.start(start, coroutine, block)return coroutine
}
  1. context: CoroutineContext
    协程上下文,包含调度器(Dispatcher)、Job、异常处理器等元素。默认值为EmptyCoroutineContext,表示使用父协程的上下文。

  2. start: CoroutineStart
    协程启动模式,枚举类型,主要包括:

    • DEFAULT:立即调度协程执行
    • LAZY:懒启动,需显式调用start()join()触发
    • ATOMIC:立即执行,但在调度前无法取消
    • UNDISPATCHED:立即在当前线程执行,直到第一个挂起点
  3. block: suspend CoroutineScope.() -> Unit
    协程体,是一个挂起函数,可在其中调用其他挂起函数。

2.协程上下文的构建与继承

newCoroutineContext(context)是关键方法,用于合并当前作用域的上下文和用户传入的上下文:

public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext {// 获取当前作用域的上下文(如GlobalScope、lifecycleScope的上下文)val combined = this.coroutineContext + context// 如果没有显式指定Job,则添加一个父Job(确保结构化并发)val debug = if (DEBUG) combined + CoroutineId(COROUTINE_ID.incrementAndGet()) else combinedreturn if (combined[Job] != null) debug else debug + Job()
}

关键点:

  • 上下文合并:通过+操作符合并上下文元素,相同类型的元素后添加的会覆盖前面的(如重复指定 Dispatcher)。
  • 默认 Job:若用户未显式指定 Job,会自动添加一个,确保协程有父子关系,实现结构化并发。

3.协程示例的创建与启动模式

根据start参数的不同,会创建不同类型的协程实例:

val coroutine = if (start.isLazy)LazyStandaloneCoroutine(newContext, block)
elseStandaloneCoroutine(newContext, active = true)

两种协程实现:

  1. LazyStandaloneCoroutine
    用于LAZY模式,协程体不会立即执行,直到调用start()join()

  2. StandaloneCoroutine
    用于其他模式,协程体会立即调度执行。

4.协程的真正启动:coroutine.start()

start()方法是协程执行的核心入口,源码如下:

public fun <R, T> CoroutineStart.invoke(coroutine: R, block: suspend R.() -> T) {when (this) {DEFAULT -> coroutine.startCoroutineCancellable(block, coroutine)ATOMIC -> coroutine.startCoroutine(block, coroutine)UNDISPATCHED -> coroutine.startCoroutineUndispatched(block, coroutine)LAZY -> Unit // 懒启动模式下不执行,等待用户显式调用start()}
}

不同启动模式的差异:

  1. DEFAULT模式
    调用startCoroutineCancellable(),允许在调度前取消协程:

    public fun <T> (suspend () -> T).startCoroutineCancellable(completion: Continuation<T>
    ) {createCoroutineUnintercepted(completion).intercepted().resumeCancellableWith(Result.success(Unit))
    }
    
  2. ATOMIC模式
    调用startCoroutine(),不允许在调度前取消:

    public actual fun <T> (suspend () -> T).startCoroutine(completion: Continuation<T>
    ) {createCoroutineUnintercepted(completion).intercepted().resumeWith(Result.success(Unit))
    }
    
  3. UNDISPATCHED模式
    调用startCoroutineUndispatched(),直接在当前线程执行直到第一个挂起点:

    internal fun <R, T> (suspend R.() -> T).startCoroutineUndispatched(receiver: R,completion: Continuation<T>
    ) {val continuation = createCoroutineUnintercepted(receiver, completion)val context = continuation.contextval uCont = continuation.intercepted()if (context[ContinuationInterceptor] == Dispatchers.Unconfined) {// 无限制调度器:直接在当前线程执行uCont.resumeWith(Result.success(Unit))} else {// 其他调度器:先切换到指定线程再执行with(context) {uCont.resumeWith(Result.success(Unit))}}
    }
    

5.async与launch的源码核心差异

asynclaunch的源码结构相似,但有两个关键区别:

public fun <T> CoroutineScope.async(context: CoroutineContext = EmptyCoroutineContext,start: CoroutineStart = CoroutineStart.DEFAULT,block: suspend CoroutineScope.() -> T
): Deferred<T> {// 创建一个携带结果的协程(继承自Job,但多了结果缓存和await()方法)val newContext = newCoroutineContext(context)val coroutine = if (start.isLazy)LazyDeferredCoroutine(newContext, block)elseDeferredCoroutine<T>(newContext, active = true)coroutine.start(start, coroutine, block)return coroutine
}

差异点:

  1. 返回值类型

    • launch返回Job(只能控制生命周期,无法获取结果)
    • async返回Deferred<T>(继承自Job,但可通过await()获取结果)
  2. 结果缓存
    DeferredCoroutine内部维护了一个Result<T>缓存,确保await()可重复获取结果,且支持多协程并发等待。

阶段总结

        Kotlin 协程的启动依赖于协程构建器和协程上下文,其中CoroutineScope.launch作为入口函数,通过合并当前作用域上下文与用户传入的上下文创建新的协程上下文,若未显式指定 Job 则自动添加以确保结构化并发;

        根据启动模式(如 DEFAULT 立即调度、LAZY 懒启动、ATOMIC 立即执行但调度前不可取消、UNDISPATCHED 立即在当前线程执行至首个挂起点)创建不同的协程实例(如 LazyStandaloneCoroutine 或 StandaloneCoroutine),并通过coroutine.start()触发协程执行,不同启动模式对应不同的执行策略;

        asynclaunch源码结构相似,但async返回继承自 Job 的 Deferred<T>类型,可通过 await () 获取结果,而launch仅返回 Job 用于控制生命周期。

http://www.dtcms.com/wzjs/173576.html

相关文章:

  • 网站做中英文英文太长怎么办百度网盘客服人工电话95188
  • 天津市政府网站建设管理办法app拉新接单平台
  • 建站经验如何在百度上开店铺
  • 招聘网站开发宁波seo快速优化课程
  • 池州网站建设公司小程序制作一个需要多少钱
  • 重庆网站模板建站深圳小程序开发公司
  • 深圳品牌网站制作报价天津百度推广开户
  • 一个网站建设花了10万元2024年4月新冠疫情结束了吗
  • kali做钓鱼网站国内最新新闻事件今天
  • 最新仿5173游戏装备交易网站 游戏币交易平台源码整合支付接口线上培训机构排名前十
  • 网站建设捌金手指下拉二七安徽百度seo公司
  • 本科毕业设计代做网站seo点击软件排名优化
  • 菏泽网站制作大型网站建设
  • 洛阳做网站公司电话杭州网站优化公司哪家好
  • 佛山微网站建设哪家专业百度推广登陆入口官网
  • 标准网站建设公司泉州网站建设优化
  • 做网站 怎么推广下载班级优化大师app
  • 做网站必须要dreameverbt兔子磁力搜索引擎最新版
  • 企业网站的制作哪家好北京最新疫情最新消息
  • 贵州网站建设系统怎么网上推广自己的产品
  • 适合个人站长的网站有哪些免费推广广告链接
  • 网站无缝背景网络营销软文范例500字
  • 徐州建设企业网站百度点击快速排名
  • 海尔网站建设水平网络营销论文毕业论文
  • unity做网站常见的网站推广方法有哪些
  • 西安网站建设-中国互联百度客服人工电话多少
  • 二级域名网站建设规范seo实战密码第三版
  • 淘宝的网站怎么做微博推广平台
  • 网站开发需要甲方提供什么新网站seo
  • 织梦html网站地图新浪网今日乌鲁木齐新闻