我正在研究Kotlin的coroutines文档,并一直很好地跟踪到这个示例。我很难理解当它找到素数时它是如何计算的,特别是filter函数的返回是如何被返回并分配给cur的,以及如何仍然从numbersFrom方法生成数字。
我添加了调试语句来尝试并跟踪正在运行的各种协同机制,但我仍然不知道它何时启动新的协同线并从其他人那里接收数字的逻辑流程。
守则:
fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
fun main(args: Array<String>) = runBlocking<Unit> {
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<Int>(context) {
var x = start
while (true) {
log("NumbersFrom Send: ${x}")
send(x++)
} // infinite stream of integers from start
}
fun filter(context: CoroutineContext, numbers: ReceiveChannel<Int>, prime: Int) = produce<Int>(context) {
for (x in numbers) {
log("filter ${x}, prime ${prime}")
if (x % prime != 0) {
send(x)
}
}
}输出:
[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发布于 2017-06-07 15:41:44
该示例的重点是实现埃拉托斯提尼筛。换句话说,通过过滤出由于素数的可分性而不能成为素数的数来寻找素数。剩下的都是质数。
让我们看看我们有什么。现在,我将忽略所有的context变量,这只会使事情更容易讨论。
首先,我们有一个名为numbersFrom的函数,它只是从2开始的一个无穷的整数序列(在本例中)。
我们还有一个叫做filter的函数,它接收一个通道,还有一个数字,大概是素数。查看返回类型,我们可以看到这个函数返回一个新的生产者。为了产生结果(在本例中为Int),可以调用send函数。查看函数的主体,filter将接受通道外的数字(通过send),并拒绝任何可被素数平均整除的数字(不做任何操作)。
例如,如果通道产生4,而素数为2,则被拒绝。另一方面,如果通道产生一个5,而质数是2,它将沿着这个数字send。现在应该很明显,filter按照自己的名字做了--读取输入,找到它喜欢的输入,并将它们发送到它的输出。
现在让我们看一下主要功能。首先,我们创建一个从2开始的数字流(这是一个巧合,第一个素数!)并将其分配给cur。到现在为止还好。
接下来,我们开始一个循环。为了让事情更容易理解,我将10减为3,但从本质上说,这个数字意味着主方法将计算多少素数。如果你想要前100个素数,把它设为100。
在循环中,通过在receive()上调用cur,从数字列表中删除第一个数字。这是一个暂停功能。正如我前面提到的,它将得到一个2作为它的第一个prime值。
现在是有趣的部分。我们将该2作为对filter的调用的基础,以及cur (目前是Int的流),并将其重新分配给cur。那么这意味着什么呢?cur现在代表了一个Ints流,过滤后不能被2整除!
在下一个循环中,我们从cur通道中取下第一个数字,它是一个3。下一个素数。为什么是3?因为filter(2)允许它通过(3 %2 != 0)。这是有趣的部分。现在我们使用cur (不可被2整除的经过过滤的数字列表),并将其与3(最近的素数)一起传递到filter函数中。现在,cur表示一个不可被2或3整除的数字流。看到这个结果了吗?
从本质上讲,在这一点上,我们有:
numbers -> filter(2) -> filter(3)或者,读另一个(不太精确的wrt协同线,但更容易理解):
filter(3, filter(2, numbers))任何使它成为cur头部的数字都是素数,因为它通过所有的过滤器。
谢谢你问我这个问题!"去学Kotlin合作社“在我的研究清单上已经有几个星期了,我早上读了很多关于它们的文章并弄明白了这一点。
https://stackoverflow.com/questions/44395147
复制相似问题