kt的协程是咋回事

背景

偶然遇到一个需求,把串行的大任务拆分成更小颗粒度的小任务依次串行执行。听起来没啥用,但是在现实场景中,是个很有效改善TTR的工作。因为主线程中的任务是不能被打断的,而所有用户操作都需要插入到队列中处理,一旦一个计算任务又大又长还在主线程,用户一定很难受。由此react提出了fiber,官宣也挺有用的。

跟协程啥关系

其实最舒服的接口就是协程类的接口,通过套嵌或顺序发起任务进行大任务拆分,以语义化dsl的方式减少阅读和理解成本,以闭包在任务间传递参数。而且协程也可以直接拿来做这个需求,毕竟自定义一个Dispatcher就能搞定一切。

几十行的轮子

然而不造轮子很没意思,不如自己写几十行实现一个只拆分任务的伪协程。
当然协程的实现还真就不是能靠现有语言特性能直接模拟出来的,因为协程其实靠的是语言在编译过程中对代码进行了二进制进行了修改(约等于transform)。但是,思路上基本是一致的,所以简单复刻就只有下面这几十行,而且可以做到不依赖复杂transform。

fun main() {
  with(SplitRun()) {
    run {
      println("aaa")
      val a = 0
      run {
        println("bbb ${a}")
        run {
          println("ccc")
        }
        run {
          println("ddd")
        }
      }
      run {
        println("eee")
      }
    }
    run {
      println("e")
    }
    commit()
  }
}

typealias Run = () -> Unit
typealias StackFrame = LinkedList<Run>

class SplitRun(private val handler: Scheduler = Schedulers.newThread()) {
  private var currentRun: Run = {}
  private val rootFrame = StackFrame()

  init {
    currentRun.setFrame(rootFrame)
  }

  fun run(runnable: Run) {
    val frame = currentRun.getFrame()
    frame.add(runnable)
  }

  fun commit() {
    handler.run {
      val run = rootFrame.poll()
      currentRun = run
      run.setFrame(StackFrame())
      run()
      val frame = run.getFrame()
      frame.asReversed().forEach { rootFrame.addFirst(it) }
      run.removeFrame()
      if (rootFrame.isNotEmpty()) {
        commit()
      }
    }
  }
}

val runFrame = mutableMapOf<Run, StackFrame>()

fun Run.setFrame(frame: StackFrame) {
  runFrame[this] = frame
}

fun Run.getFrame(): StackFrame {
  return runFrame[this]!!
}

fun Run.removeFrame() {
  runFrame.remove(this)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值