当前位置:嗨网首页>书籍在线阅读

28-管道与质数

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

12.7.2 管道与质数

使用协程可以生成一个无穷质数序列,为了方便调用方控制协程运行的位置,需要在定义时引入一个显式上下文参数context。

fun numbersFrom(context: CoroutineContext, start: Int) = produce<Int>(context) {
    var x = start
    while (true) send(x++) 
}

定义一个接收管道数据的函数,并对接收的数字流进行质数过滤。

fun filterPrimes(context: CoroutineContext, numbers: ReceiveChannel<Int>, prime: Int) = produce<Int>(context) {
    for (x in numbers) if (x % prime != 0) send(x)
}

然后定义一个测试函数,并在主线程中运行整合的管道。

fun testPrimes() = runBlocking {
    var producerJob = numbersFrom(coroutineContext, 2)
    //输出100个质数
    for (i in 1..10) {
        val prime = producerJob.receive()
        println("${prime}")
        producerJob = filterPrimes(coroutineContext, producerJob, prime)
    }
}

运行上面的代码,输出的结果如下。

2
3
5
7
11
13
17
19
23
29

除了使用普通的协程来构建管道之外,还可以使用标准库中的buildIterator协程来构建管道。但是使用通道中的管道的好处在于,如果在CommonPool中运行协程,则可以利用CPU多内核处理的优势。

无论如何,使用上面例子中的方式来寻找质数是非常不切实际的,实际上,管道确实涉及一些其他方式的挂起调用操作(如异步调用、远程服务),而且这些管道不能使用buildSequence/buildIterator来构建,因为它们不允许有任意的挂起操作。