Kotlin Coroutines文档中的素数示例如何工作?

我正在通过Kotlin的协程文件,并且一直沿用这个例子。 当我发现一个素数时,我很难理解它是如何计算的,特别是如何从filter函数返回并分配给cur ,以及如何从numbersFrom方法生成数字。

我已经添加了调试语句,以尝试并遵循正在运行的各种协程,但是我仍然失去了启动新协程并从其他人接收数字的逻辑流程。

https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#prime-numbers-with-pipeline

代码:

 fun log(msg: String) = println("[${Thread.currentThread().name}] $msg") fun main(args: Array) = runBlocking { var cur = numbersFrom(context, 2) for (i in 1..10) { val prime = cur.receive() println(prime) cur = filter(context, cur, prime) } } fun numbersFrom(context: CoroutineContext, start: Int) = produce(context) { var x = start while (true) { log("NumbersFrom Send: ${x}") send(x++) } // infinite stream of integers from start } fun filter(context: CoroutineContext, numbers: ReceiveChannel, prime: Int) = produce(context) { for (x in numbers) { log("filter ${x}, prime ${prime}") if (x % prime != 0) { send(x) } } } 

Outout:

 [main @coroutine#2] NumbersFrom Send: 2 [main @coroutine#2] NumbersFrom Send: 3 2 [main @coroutine#3] filter 3, prime 2 [main @coroutine#2] NumbersFrom Send: 4 [main @coroutine#2] NumbersFrom Send: 5 3 [main @coroutine#3] filter 4, prime 2 [main @coroutine#3] filter 5, prime 2 [main @coroutine#4] filter 5, prime 3 [main @coroutine#2] NumbersFrom Send: 6 [main @coroutine#3] filter 6, prime 2 5 [main @coroutine#2] NumbersFrom Send: 7 [main @coroutine#2] NumbersFrom Send: 8 [main @coroutine#3] filter 7, prime 2 [main @coroutine#3] filter 8, prime 2 [main @coroutine#4] filter 7, prime 3 [main @coroutine#2] NumbersFrom Send: 9 [main @coroutine#2] NumbersFrom Send: 10 [main @coroutine#5] filter 7, prime 5 [main @coroutine#3] filter 9, prime 2 [main @coroutine#3] filter 10, prime 2 7 [main @coroutine#4] filter 9, prime 3 [main @coroutine#2] NumbersFrom Send: 11 [main @coroutine#2] NumbersFrom Send: 12 [main @coroutine#3] filter 11, prime 2 [main @coroutine#3] filter 12, prime 2 [main @coroutine#4] filter 11, prime 3 [main @coroutine#2] NumbersFrom Send: 13 [main @coroutine#2] NumbersFrom Send: 14 [main @coroutine#5] filter 11, prime 5 [main @coroutine#3] filter 13, prime 2 [main @coroutine#3] filter 14, prime 2 [main @coroutine#6] filter 11, prime 7 [main @coroutine#4] filter 13, prime 3 [main @coroutine#2] NumbersFrom Send: 15 [main @coroutine#2] NumbersFrom Send: 16 11 [main @coroutine#5] filter 13, prime 5 [main @coroutine#3] filter 15, prime 2 [main @coroutine#3] filter 16, prime 2 [main @coroutine#6] filter 13, prime 7 [main @coroutine#4] filter 15, prime 3 [main @coroutine#2] NumbersFrom Send: 17 [main @coroutine#2] NumbersFrom Send: 18 [main @coroutine#7] filter 13, prime 11 [main @coroutine#3] filter 17, prime 2 [main @coroutine#3] filter 18, prime 2 13 [main @coroutine#4] filter 17, prime 3 [main @coroutine#2] NumbersFrom Send: 19 [main @coroutine#2] NumbersFrom Send: 20 [main @coroutine#5] filter 17, prime 5 [main @coroutine#3] filter 19, prime 2 [main @coroutine#3] filter 20, prime 2 [main @coroutine#6] filter 17, prime 7 [main @coroutine#4] filter 19, prime 3 [main @coroutine#2] NumbersFrom Send: 21 [main @coroutine#2] NumbersFrom Send: 22 [main @coroutine#7] filter 17, prime 11 [main @coroutine#5] filter 19, prime 5 [main @coroutine#3] filter 21, prime 2 [main @coroutine#3] filter 22, prime 2 [main @coroutine#8] filter 17, prime 13 [main @coroutine#6] filter 19, prime 7 [main @coroutine#4] filter 21, prime 3 [main @coroutine#2] NumbersFrom Send: 23 [main @coroutine#2] NumbersFrom Send: 24 17 [main @coroutine#7] filter 19, prime 11 [main @coroutine#3] filter 23, prime 2 [main @coroutine#3] filter 24, prime 2 [main @coroutine#8] filter 19, prime 13 [main @coroutine#4] filter 23, prime 3 [main @coroutine#2] NumbersFrom Send: 25 [main @coroutine#2] NumbersFrom Send: 26 [main @coroutine#9] filter 19, prime 17 [main @coroutine#5] filter 23, prime 5 [main @coroutine#3] filter 25, prime 2 [main @coroutine#3] filter 26, prime 2 19 [main @coroutine#6] filter 23, prime 7 [main @coroutine#4] filter 25, prime 3 [main @coroutine#2] NumbersFrom Send: 27 [main @coroutine#2] NumbersFrom Send: 28 [main @coroutine#7] filter 23, prime 11 [main @coroutine#5] filter 25, prime 5 [main @coroutine#3] filter 27, prime 2 [main @coroutine#3] filter 28, prime 2 [main @coroutine#8] filter 23, prime 13 [main @coroutine#4] filter 27, prime 3 [main @coroutine#2] NumbersFrom Send: 29 [main @coroutine#2] NumbersFrom Send: 30 [main @coroutine#9] filter 23, prime 17 [main @coroutine#3] filter 29, prime 2 [main @coroutine#3] filter 30, prime 2 [main @coroutine#10] filter 23, prime 19 [main @coroutine#4] filter 29, prime 3 [main @coroutine#2] NumbersFrom Send: 31 [main @coroutine#2] NumbersFrom Send: 32 23 [main @coroutine#5] filter 29, prime 5 [main @coroutine#3] filter 31, prime 2 [main @coroutine#3] filter 32, prime 2 [main @coroutine#6] filter 29, prime 7 [main @coroutine#4] filter 31, prime 3 [main @coroutine#2] NumbersFrom Send: 33 [main @coroutine#2] NumbersFrom Send: 34 [main @coroutine#7] filter 29, prime 11 [main @coroutine#5] filter 31, prime 5 [main @coroutine#3] filter 33, prime 2 [main @coroutine#3] filter 34, prime 2 [main @coroutine#8] filter 29, prime 13 [main @coroutine#6] filter 31, prime 7 [main @coroutine#4] filter 33, prime 3 [main @coroutine#2] NumbersFrom Send: 35 [main @coroutine#2] NumbersFrom Send: 36 [main @coroutine#9] filter 29, prime 17 [main @coroutine#7] filter 31, prime 11 [main @coroutine#3] filter 35, prime 2 [main @coroutine#3] filter 36, prime 2 [main @coroutine#10] filter 29, prime 19 [main @coroutine#8] filter 31, prime 13 [main @coroutine#4] filter 35, prime 3 [main @coroutine#2] NumbersFrom Send: 37 [main @coroutine#2] NumbersFrom Send: 38 [main @coroutine#11] filter 29, prime 23 [main @coroutine#9] filter 31, prime 17 [main @coroutine#5] filter 35, prime 5 [main @coroutine#3] filter 37, prime 2 [main @coroutine#3] filter 38, prime 2 29 [main @coroutine#10] filter 31, prime 19 [main @coroutine#4] filter 37, prime 3 [main @coroutine#2] NumbersFrom Send: 39 

这个例子的要点是实施Eratosthenes筛 。 换句话说,通过筛选出因为可分性而不能成为素数的数字来寻找素数。 剩下的东西是一个主要的东西。

让我们看看我们有什么。 我现在要忽略所有的contextvariables,只是让事情更容易谈论。

首先,我们有一个叫做numbersFrom的函数,这个函数只是从2开始的无穷序列(在这种情况下)。

我们也有一个叫做filter函数,它包含一个频道和一个可能是素数的数字。 看看返回types,我们可以看到这个函数返回一个新的生产者。 为了产生结果(在这种情况下为Int ),可以调用sendfunction。 查看函数的主体, filter将接受离开通道的数字(通过send ),并拒绝任何能被素数均匀分配的东西(不做任何事情)。

例如,如果频道产生4而素数是2,则被拒绝。 另一方面,如果频道产生一个5并且素数是2,它将一起send该数字。 它现在应该变得很明显, filter的名字就是说 – 读输入,find它喜欢的东西,把它们发送到它的输出。

现在我们来看看主要的function。 首先,我们创建一个从2开始的数字流(这是一个巧合,第一个素数!),并将其分配给cur 。 到现在为止还挺好。

接下来,我们开始一个循环。 我把10减到3使事情变得容易理解,但基本上这个数字意味着主要方法计算多少个素数。 如果你想要第一个100个素数,把它设置为100。

在循环中,我们通过在cur上调用receive()来从数字列表中取出第一个数字。 这是暂停function。 正如我上面提到的那样,它会得到一个2作为第一个prime价值。

现在这里是有趣的部分。 我们把这个2作为filter调用的基础,并将其与目前为Int流的cur进行filter ,并将其重新分配给cur 。 那么这是什么意思? 现在代表一个Ints流,过滤不能被2整除!

在下一个循环中,我们从cur通道中取出第一个数字,它是3.下一个数字。 为什么是3? 因为filter(2)允许它通过(3%2!= 0)。 这是有趣的部分。 现在我们把cur(一个不能被2整除的数字的过滤列表)和3(我们最近的素数)一起传递给一个filter函数。 现在, cur代表一个不能被2或3整除的数字流。看看这是怎么回事?

本质上在这一点上,我们有这样的:

 numbers -> filter(2) -> filter(3) 

或者,阅读另一个(不太精确的协程,但更容易图片):

 filter(3, filter(2, numbers)) 

任何使它成为头部的数字都是主要的,因为它通过了所有的filter。

感谢您提出这个问题! “ 去学习Kotlin Coroutines ”已经在我的研究名单上好几个星期了,我早上读了一些关于他们的文章,并弄清楚了这一点。

确保你了解Eratosthenes的Sieve算法的逻辑。

看animation : filter(2)显示为红色。 filter(3)是绿色的, filter(5)是蓝色的等等