Kotlin替代Python的协同程序产生并发送

时间:2017-05-27 07:04:44

标签: python concurrency kotlin channel coroutine

以下python coroutine片段的Kotlin惯用替代方案:

def generator():
  c = 1
  while True:
    op = yield c
    if op == 'inc':
      c += 1
    elif op == 'mult':
      c *= 2

# main
g = generator()
a = g.send(None) # start
b = g.send('inc')
c = g.send('mult')
d = g.send('inc')

print([a, b, c, d]) # 1, 2, 4, 5

所以我需要从协程中获取值(通过通道?),还要将值发送回协程。我需要两个频道吗?

1 个答案:

答案 0 :(得分:3)

在Python和ES6中存在的那种双向生成器在Kotlin中并不是真正的惯用语,因为Kotlin是一种静态类型语言,因此使用双向生成器非常笨拙。只需查看上面代码中的g.send(None)即可了解其原因。因此,Kotlin标准库和支持库中都没有提供双向生成器的实现。

然而,Kotlin语言中的协程支持是通用的,如果需要,可以实现双向生成器,就像在Python和ES6中一样。相应的实现可用here,只需几行代码即可。

通过上面的双向生成器实现,您的Python代码可以直接逐行转换为Kotlin:

fun generator() = generate<Int, String> {
    var c = 1
    while (true) {
        val op = yield(c)
        when (op) {
            "inc" -> c += 1
            "mult" -> c *= 2
        }
    } 
}

fun main(args: Array<String>) {
    val g = generator()
    val a = g.next("") // start
    val b = g.next("inc")
    val c = g.next("mult")
    val d = g.next("inc")
    println("$a $b $c $d") // 1, 2, 4, 5
}

此代码与其Python版本一样有效,但由于众多原因,它不是惯用语。首先,Kotlin中的协程支持允许定义任意挂起函数,因此可以以类型安全的方式表达类似的行为,而不需要使用任意的开始标记,也不使用字符串来表示操作。您可以直接定义具有incmult作为其第一类挂起操作的对象,或者至少更改实现,以便不需要虚拟启动调用。欢迎您学习coroutines design document,它解释了Kotlin提供的所有低级原语,并提供了许多示例来帮助您入门。