¿Cómo funciona el ejemplo de los numbers primos de la documentation de Corotines de Kotlin?

Estoy revisando la documentation de corotines para Kotlin y estaba siguiendo bastante bien hasta este ejemplo. Me está resultando realmente difícil entender cómo se calcula cuando encuentra un número primo, y específicamente cómo se devuelve y se asigna el retorno de la function de filter a cur , así como también se siguen produciendo numbers a partir del método numbersFrom .

He agregado instrucciones de debugging para tratar de seguir las distintas corutinas que se están ejecutando, pero todavía estoy perdido en el flujo lógico de cuando comienza nuevas corutinas y recibe numbers de otros.

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

El código:

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

Fuera fuera:

 [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 

Solutions Collecting From Web of "¿Cómo funciona el ejemplo de los numbers primos de la documentation de Corotines de Kotlin?"

El objective del ejemplo es implementar el Tamiz de Eratóstenes . En otras palabras, para encontrar numbers primos filtrando los numbers que no pueden ser primos debido a su divisibilidad. Todo lo que queda es un primo.

Miremos lo que tenemos. Voy a ignorar todas las variables de context por ahora, simplemente hace las cosas más fáciles de hablar.

Primero, tenemos una function llamada numbersFrom , que es solo una secuencia interminable de integers que comienzan en 2 (en este caso).

También tenemos la function llamada filter , que toma un canal, y un número que presumiblemente es primo. Mirando el tipo de retorno, podemos ver que esta function devuelve un nuevo productor. Para producir resultados ( Int s en este caso), se puede llamar a la function de send . Al observar el cuerpo de la function, el filter aceptará numbers del canal (a través del send ) y RECHAZAR todo lo que sea divisible por el número primo (sin hacer nada).

Por ejemplo, si el canal produce un 4 y el primo es un 2, eso es rechazado. Por otro lado, si el canal produce un 5 y el primo es un 2, send ese número. Ahora debería ser obvio que el filter hace lo que dice su nombre: lea las inputs, encuentre las que le gustan, envíelas a su salida.

Ahora veamos la function principal. Primero creamos un flujo de numbers que comienza en 2 (¡qué casualidad, el primer primo!) Y lo asignamos a cur . Hasta aquí todo bien.

A continuación, comenzamos un ciclo. Reduje el 10 a un 3 para hacer las cosas más fáciles de entender, pero esencialmente ese número significa cuántos numbers primos calculará el método principal. Si quiere los primeros 100 numbers primos, configúrelo en 100.

En el ciclo, sacamos el primer número de la list de numbers, llamando a receive() en cur . Esta es una function de suspensión. Y como mencioné anteriormente, obtendrá un 2 como su prime valor prime .

Y ahora aquí está la parte divertida. Tomamos ese 2 y lo usamos como base para una llamada para filter , junto con cur , que actualmente es la stream de Int , y reasignar eso a cur . ¿Entonces que significa eso? cur ahora representa una stream de Ints, filtrada para NO ser divisible por 2 !.

En el siguiente ciclo, sacamos el primer número del canal cur , y es un 3. El siguiente primo. ¿Por qué es un 3? Porque el filter(2) le permitió pasar (3% 2! = 0). Esta es la parte divertida. Ahora tomamos cur (una list filtrada de numbers que no son divisibles por 2) y lo pasamos a una function de filter , junto con 3 (nuestro primo más reciente). Ahora cur representa una secuencia de numbers no divisibles por 2 o 3. ¿A dónde va esto?

Esencialmente en este punto tenemos esto:

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

O bien, lea otra (corutinas less precisas pero más fáciles de ver):

 filter(3, filter(2, numbers)) 

Cualquier número que llegue a la cabeza de cur es primordial, porque pasó a través de todos los filters.

Gracias por hacer esta pregunta! " Ve a aprender Kotlin Coroutines " ha estado en mi list de investigación durante un par de semanas y tuve un buen día leyendo sobre ellos y averigüé esto.

Asegúrese de comprender la lógica del algorithm Sieve of Eratosthenes .

Mira la animation : el filter(2) se muestra en color rojo. filter(3) es verde, el filter(5) es azul, etc.