kotlin coroutines in practice
play

Kotlin Coroutines in Practice Roman Eliza zarov !"#$%&( - PowerPoint PPT Presentation

Kotlin Coroutines in Practice Roman Eliza zarov !"#$%&( ) )&!"#$%&( Coroutines recap Coroutines are like light-weight threads suspend fun main() { val jobs = List (100_000) { GlobalScope. launch { delay (5000)


  1. fun CoroutineScope.downloader( references: ReceiveChannel<Reference>, ) = launch { val requested = mutableSetOf <Location>() for (ref in references) { val location = ref.resolveLocation() if (requested.add(location)) { // schedule download } // ... wait for result ... processContent (ref, content) } }

  2. fun CoroutineScope.downloader( references: ReceiveChannel<Reference>, ) = launch { val requested = mutableSetOf <Location>() for (ref in references) { val location = ref.resolveLocation() if (requested.add(location)) { // schedule download } // ... wait for result ... processContent (ref, content) } }

  3. f un Cor out i neScope. downl oader ( r ef er ences: Recei veChannel <Ref er ence>, ) = launch { r equest ed = mutableSetOf <Locat i on>( ) val f or ( r ef i n r ef er ences) { l ocat i on = r ef . r esol veLocat i on( ) val i f ( r equest ed. add( l ocat i on) ) { // schedule download } // ... wait for result ... processContent ( r ef , cont ent ) } }

  4. fun CoroutineScope.downloader( references: ReceiveChannel<Reference>, ) = launch { val requested = mutableSetOf <Location>() for (ref in references) { val location = ref.resolveLocation() if (requested.add(location)) { launch { … } } // ... wait for result ... processContent (ref, content) } } Coroutines are cheap! What could go wrong?

  5. fun CoroutineScope.downloader( references: ReceiveChannel<Reference>, ) = launch { val requested = mutableSetOf <Location>() for (ref in references) { Child val location = ref.resolveLocation() if (requested.add(location)) { launch { … } } // ... wait for result ... processContent (ref, content) } }

  6. fun CoroutineScope.downloader( references: ReceiveChannel<Reference>, ) = l aunch { val requested = m f <Location>() ut abl eSet O for (ref in references) { val location = ref.resolveLocation() if (requested.add(location)) { l aunch { … } } / / . . . wai t f or r esul t . . . pr ocessCont ent (ref, content) } } Coroutines are cheap! But the work they do…

  7. Limiting concurrency

  8. Worker pool Worker 1 Worker 2 references locations References Worker 3 … Downloader Worker N

  9. fun Cor out i neScope. downl oader ( r ef er ences: Recei veChannel <Ref er ence>, l ocat i ons: SendChannel <Locat i on> )

  10. fun CoroutineScope.downloader( references: ReceiveChannel<Reference>, locations: SendChannel<Location> ) = launch { val requested = mutableSetOf <Location>() for (ref in references) { val location = ref.resolveLocation() if (requested.add(location)) { locations.send(location) } } }

  11. fun CoroutineScope.worker( locations: ReceiveChannel<Location> )

  12. fun CoroutineScope.worker( locations: ReceiveChannel<Location> )

  13. fun CoroutineScope.worker( locations: ReceiveChannel<Location> ) = launch { for (loc in locations) { val content = downloadContent (loc) processContent (ref, content) } }

  14. f un CoroutineScope.worker( Fan-out locations: ReceiveChannel<Location> ) = launch { f or (loc i n locations) { content = downloadContent (loc) val processContent (ref, content) } }

  15. fun CoroutineScope.worker( locations: ReceiveChannel<Location> ) = launch { for (loc in locations) { val content = downloadContent (location) processContent (ref, content) } }

  16. fun CoroutineScope.worker( locations: ReceiveChannel<Location> ) = launch { for (loc in locations) { val content = downloadContent (loc) processContent (ref, content) } }

  17. fun Cor out i neScope. wor ker ( l ocat i ons: Recei veChannel <Locat i on> ) = launch { for ( l oc in l ocat i ons) { val cont ent = downloadContent ( l oc) processContent ( r ef , cont ent ) } }

  18. Worker 1 Worker 2 References Worker 3 … Downloader Worker N

  19. Ref s ↔ Locs Worker 1 Worker 2 Ref er ences Worker 3 … Downl oader l ocat i on & cont ent Worker N

  20. data class LocContent( val loc : Location, val content : Content)

  21. data class LocContent( val loc : Location, val content : Content) fun CoroutineScope.worker( locations: ReceiveChannel<Location>, contents: SendChannel<LocContent> )

  22. data class LocContent( val loc : Location, val content : Content) fun CoroutineScope.worker( locations: ReceiveChannel<Location>, contents: SendChannel<LocContent> ) = launch { for (loc in locations) { val content = downloadContent (loc) contents.send(LocContent(loc, content)) } }

  23. Worker 1 locations Worker 2 References Worker 3 … Downloader contents Worker N

  24. fun CoroutineScope.downloader( references: ReceiveChannel<Reference>, locations: SendChannel<Location>, contents: ReceiveChannel<LocContent> )

  25. fun Cor out i neScope. downl oader ( r ef er ences: Recei veChannel <Ref er ence>, l ocat i ons: SendChannel <Locat i on>, Hmm…. cont ent s: Recei veChannel <LocCont ent > ) = launch { val r equest ed = mutableSetOf <Locat i on>( ) for ( r ef in r ef er ences) { val l ocat i on = r ef . r esol veLocat i on( ) if ( r equest ed. add( l ocat i on) ) { l ocat i ons. send( l ocat i on) } } }

  26. Select

  27. sel ect { r ef er ences. onRecei ve { r ef - > … } cont ent s. onRecei ve { ( l oc, cont ent ) - > … } }

  28. select { references. onReceive { ref -> … } contents. onReceive { (loc, content) -> … } }

  29. select<Unit> { references. onReceive { ref -> … } contents. onReceive { (loc, content) -> … } }

  30. launch { val requested = mutableMapOf <Location, MutableList<Reference>>() … }

  31. launch { val r equest ed = mutableMapOf <Locat i on, M ut abl eLi st <Ref er ence>>( ) while ( true ) { sel ect <Uni t > { r ef er ences. onReceive { r ef -> … } cont ent s. onReceive { ( l oc, cont ent ) -> … } } } }

  32. launch { val r equest ed = mutableMapOf <Locat i on, M ut abl eLi st <Ref er ence>>( ) while ( true ) { sel ect <Uni t > { r ef er ences. onReceive { r ef -> … } cont ent s. onReceive { ( l oc, cont ent ) -> … } } } }

  33. launch { val requested = mutableMapOf <Location, MutableList<Reference>>() while ( true ) { select<Unit> { references. onReceive { ref -> val loc = ref.resolveLocation() … } contents. onReceive { (loc, content) -> … } } } }

  34. launch { val requested = mutableMapOf <Location, MutableList<Reference>>() while ( true ) { select<Unit> { references. onReceive { ref -> val loc = ref.resolveLocation() val refs = requested[loc] … } contents. onReceive { (loc, content) -> … } } } }

  35. launch { val requested = mutableMapOf <Location, MutableList<Reference>>() while ( true ) { select<Unit> { references. onReceive { ref -> val loc = ref.resolveLocation() val refs = requested[loc] if (refs == null ) { requested[loc] = mutableListOf (ref) locations.send(loc) } } contents. onReceive { (loc, content) -> … } } } }

  36. l aunch { val requested = m f <Location, MutableList<Reference>>() ut abl eM apO while ( true ) { select<Unit> { references. onReceive { ref -> val loc = ref.resolveLocation() val refs = requested[loc] if (refs != null ) { requested[loc] = m f (ref) ut abl eLi st O locations.send(loc) } else { refs.add(ref) } } contents. onReceive { (loc, content) -> … } } } }

  37. launch { val requested = mutableMapOf <Location, MutableList<Reference>>() while ( true ) { select<Unit> { references. onReceive { ref -> val loc = ref.resolveLocation() val refs = requested[loc] if (refs != null ) { No concurrency requested[loc] = mutableListOf (ref) locations.send(loc) No synchronization } else { refs.add(ref) } } contents. onReceive { (loc, content) -> … } } } }

  38. launch { val r equest ed = mutableMapOf <Locat i on, M ut abl eLi st <Ref er ence>>( ) while ( true ) { sel ect <Uni t > { r ef er ences. onReceive { r ef -> … } cont ent s. onReceive { ( l oc, cont ent ) -> val r ef s = r equest ed. r em ove( l oc) ! ! for ( r ef in r ef s) { processContent ( r ef , cont ent ) } } } } }

  39. Putting it all together

  40. Worker 1 locations Worker 2 References Worker 3 references … Downloader contents Worker N

  41. Worker 1 locations Worker 2 References Worker 3 references … Downloader contents Worker N

  42. fun CoroutineScope.processReferences( references: ReceiveChannel<Reference> )

  43. fun Cor out i neScope. pr ocessRef er ences( r ef er ences: Recei veChannel <Ref er ence> )

  44. fun CoroutineScope.processReferences( references: ReceiveChannel<Reference> ) { val locations = Channel <Location>() val contents = Channel <LocContent>() repeat ( N_WORKERS ) { worker (locations, contents) } downloader (references, locations, contents) }

Recommend


More recommend