我正在阅读Kotlin的协程文档,并且在完成本示例之前一直很好。我很难理解它在找到质数时如何进行计算,特别是如何返回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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
外出:
[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
Run Code Online (Sandbox Code Playgroud)
该示例的重点是实现Eratosthenes筛。换句话说,通过滤除因数不可分的质数来查找质数。剩下的一切都是素数。
让我们看看我们有什么。现在,我将忽略所有context变量,这只会使事情更容易谈论。
首先,我们有一个名为的函数numbersFrom,它只是从2开始的无穷整数序列(在这种情况下)。
我们还有filter一个名为的函数,它接收一个通道,以及一个可能是质数的数字。查看返回类型,我们可以看到该函数返回了一个新的生产者。为了产生结果(Int在本例中为s),send可以调用该函数。查看函数的主体,filter将接受通道外的数字(通过send),并拒绝可被质数整除的任何内容(不执行任何操作)。
例如,如果通道产生4,而素数是2,则拒绝。另一方面,如果通道产生5,质数为2,则send该数字也会随之增加。现在应该很明显地filter做到了它的名字所说的-读取输入,找到喜欢的输入,并将它们发送到输出。
现在让我们看一下主要功能。首先,我们创建一个从2开始的数字流(巧合,第一个质数!),并将其分配给cur。到目前为止,一切都很好。
接下来,我们开始循环。我将10减为3,以使事情更容易理解,但从本质上讲,该数字表示主要方法将计算多少个素数。如果要使用前100个素数,请将其设置为100。
在循环中,我们采取的第一个数字关闭号码列表,通过调用receive()上cur。这是一个暂停功能。而且如上所述,它的第一个prime值将为2 。
现在这是有趣的部分。我们2以此为基础,并将其作为对filter以及cur当前当前的Ints 流的调用的基础,然后将其重新分配给cur。那是什么意思呢?cur现在表示一个整数流,过滤后不能被2整除!
在下一个循环中,我们从cur通道中取出第一个数字,它是3。下一个质数。为什么是3?因为filter(2)允许它通过(3%2!= 0)。这是有趣的部分。现在我们获取cur(一个不能被2整除的数字过滤列表),并将其filter与3(我们最近的质数)一起传递给函数。现在cur表示不被2或3整除的数字流。
从本质上来说,我们有以下几点:
numbers -> filter(2) -> filter(3)
Run Code Online (Sandbox Code Playgroud)
或者,再读一遍(不太精确的wrt协程,但是更容易描绘):
filter(3, filter(2, numbers))
Run Code Online (Sandbox Code Playgroud)
使其成为开头的任何数字cur都是质数,因为它通过了所有过滤器。
感谢您提出这个问题!“ 去学习Kotlin Coroutines ”已经在我的研究列表上呆了几周,我早上好阅读有关它们的信息,并弄清楚了这一点。
| 归档时间: |
|
| 查看次数: |
530 次 |
| 最近记录: |