协程用伪代码的方式讲解Continuation

245 阅读2分钟

关于Android-Kotlin协程,我们要牢记,它就是个线程框架,它的唯一作用是:

把异步代码用同步的方式来写!

用更容易理解的话来说,就是

由它来帮我们做切换线程的操作!

我尝试用伪代码的方式,把它描述清楚

以这样一段代码为例:

scope.launch(主线程) {
    这里是一堆非suspend代码-01
    withContext (IO线程) {
        调用接口
    }
    这里是一堆非suspend代码-02
    withContext (Work线程) {
        数据排序
    }
    这里是一堆非suspend代码-03
}

对于线程来说,最重要的东西是Runnable,Android切换主线程,是Handler.post(Runnable),线程池执行任务,也是executor.execute(Runnable)。 既然协程的唯一作用就是帮我们切换线程,它必定逃不脱把代码转换为Runnable。

转换的第一步: 把scope内的代码直接变成Runnable

scope.launch(主线程) {
    handler.post: new Runnable { 这里是一堆非suspend代码-01 }
    IO线程池.execute: new Runnable { 调用接口 }
    handler.post: new Runnable { 这里是一堆非suspend代码-02 }
    Work线程池.execute: new Runnable { 数据排序 }
    handler.post: new Runnable { 这里是一堆非suspend代码-03 }
}

这样,至少可以完成 切换线程 这一需求。只是现在它还不是串行的。

转换的第二步: 为了让它串行,需要先让它知道串行的顺序

想让它串行,就必须让原来的多个互不关联的Runnable之间产生关联,最简单的办法就是提供一个全局变量,由这个全局变量来记录当前执行到了哪一步。

每个Runnable执行完成后,就更新状态

scope.launch(主线程) {
    int state = 0 // 我来记录当前执行到哪一步了
    
    handler.post: new Runnable { 
        这里是一堆非suspend代码-01
        state = 1
    }
    IO线程池.execute: new Runnable { 
        调用接口 
        state = 2
    }
    handler.post: new Runnable { 
        这里是一堆非suspend代码-02 
        state = 3
    }
    Work线程池.execute: new Runnable { 
        数据排序 
        state = 4
    }
    handler.post: new Runnable { 
        这里是一堆非suspend代码-03 
        state = 5
    }
}

转换的第三步: 把它们串起来

顺序已经有了,把它们串行执行,就只需要一个中转处理

scope.launch(主线程) {
    int state = 0 // 我来记录当前执行到哪一步了
    
    Runnable1 = { 
        这里是一堆非suspend代码-01
        state = 1
        runnableDone()
    }
    Runnable2 = { 
        调用接口 
        state = 2
        runnableDone()
    }
    Runnable3 = { 
        这里是一堆非suspend代码-02 
        state = 3
        runnableDone()
    }
    Runnable4 = { 
        数据排序 
        state = 4
        runnableDone()
    }
    Runnable5 = { 
        这里是一堆非suspend代码-03 
        state = 5
        runnableDone()
    }
    
    void runnableDone() {
        when (state):
        0: handler.post Runnable1
        1: IO线程池.execute Runnable2
        2: handler.post Runnable3
        3: Work线程池.execute Runnable4
        4: handler.post Runnable5
        5: 完成
    }
}

start() -> ResumeWith(0) -> state=0 & runnableDone()

完成,原来的异步代码就变成了同步的形式。