How does the primes example from the Kotlin Coroutines documentation work?

I go through the accompanying documentation for Kotlin and follow well up to this example. It is very difficult for me to understand how it calculates when it finds a prime number, and specifically how the return from a function is filter

returned and assigned cur

, and also still produces numbers from numbersFrom

.

I've added debug statements to try and execute the various coroutines being executed, but I still get lost in the logical flow when it starts new coroutines and gets numbers from others.

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

Code:

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)
        }
    }
}

      

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

      

+3


source to share


2 answers


The point of the example is to implement the Sieve of Eratosthenes . In other words, find prime numbers by filtering out numbers that cannot be primary due to their divisibility. Everything else is simple.

Let's see what we have. I'll ignore all the variables for now context

, it just simplifies the discussion.

First, we have a function called numbersFrom

, which is simply an infinite sequence of integers starting at 2 (in this case).

We also have a function called filter

that takes in a pipe, and a number that is presumably prime. Looking at the return type, we can see that this function returns a new manufacturer. You Int

can call a function to get the results ( in this case) send

. If you look at the body of the function, it filter

will accept numbers from the channel (through send

) and DISABLE everything that is evenly divisible by a prime number (without doing anything).

For example, if the channel creates 4 and the stroke is 2, this is rejected. On the other hand, if the channel produces 5 and the stroke is 2, it will be send

that number. It should now become obvious what filter

does what his name says - read the inputs, find the ones he likes, send them along with his output.

Now let's look at the main function. We first create a stream of numbers starting at 2 (what a coincidence, the first is prime!) And assign that cur

. So far so good.

Then we start the cycle. I've reduced 10 to 3 to make it easier to understand, but basically this number means how many primes the main method will calculate. If you want to get the first 100 primes, set the value to 100.

In the loop, we take the first number from the list of numbers by calling receive()

on cur

. This is a pause function. And as I mentioned above, it will get 2 as the first value prime

.



Now here's the fun part. Let's take that 2

and use it as a base to call filter

along with cur

, which is currently the stream Int

s, and reassign that to cur

. So what does this mean? cur

now represents a stream of Ints, filtered to NOT be divisible by 2 !.

In the next loop we take the first number from the channel cur

, which is 3. The next one is simple. Why is it 3? Because I filter(2)

let him pass (3% 2! = 0). This is the interesting part. Now we take cur (a filtered list of numbers that are not divisible by 2) and pass it to the function filter

, as well as 3 (our last prime). Now cur

represents a stream of numbers that are not divisible by 2 or 3. See where this is happening?

Essentially at this point we have the following:

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

      

Or, read another one (less precise wrout coroutines, but easier for the image):

filter(3, filter(2, numbers))

      

Any number that makes it to the beginning cur

is prime because it went through all the filters.

Thanks for asking this question! " Go learn Kotlin Coroutines " has been on my research list for a couple of weeks and I read well about them and figured it out.

+1


source


Make sure you understand the logic behind the Sieve of Eratosthenes algorithm .



Look at animation : filter(2)

displayed in red. filter(3)

green, filter(5)

- blue, etc.

+1


source







All Articles