Slide 1

Slide 1 text

Coroutines and Threads ਂ͍͍ษڧձ

Slide 2

Slide 2 text

લճ·Ͱ͸ • Threadͷىಈํ๏͸Ұ͚ͭͩ
 - ThreadΫϥεΛStartͯ͠Runnable::runΛݺͿ • Handler͸ThreadΛ࡞Βͳ͍ • Coroutine͕Α͘෼͔Βͳ͍ • Coroutine͸ThreadΑΓ”ܰྔత”Β͍͠

Slide 3

Slide 3 text

ࠓճௐ΂ͨ͜ͱ • Coroutine΋ཁ͸ThreadͳͷͰ͸ͳ͍͔ɺͱ͍ ͏͜ͱΛ໌Β͔ʹ͢Δ
 - Coroutineͩͬͯຐ๏͡Όͳ͍͸ͣ • ͳͥThreadΑΓ΋”ܰྔత”ͱݴΘΕ͍ͯΔ͔Λ ໌Β͔ʹ͢Δ
 - ThreadΑΓ͍ܰͱ͸ʁ

Slide 4

Slide 4 text

Coroutineͷ࣮૷Λݟ͍ͯ͘

Slide 5

Slide 5 text

CoroutineΛىಈ͢Δ // UI.kt
 private fun start(block: suspend () -> Unit): Job { return uiScope.launch { block() } } 
 // Builders.common.kt public fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job { val newContext = newCoroutineContext(context) val coroutine = if (start.isLazy) LazyStandaloneCoroutine(newContext, block) else StandaloneCoroutine(newContext, active = true) coroutine.start(start, coroutine, block) return coroutine } launchͰCoroutine͕ىಈ͢Δ CoroutineContext?

Slide 6

Slide 6 text

CoroutineContextΛ࡞Δ // CoroutineContext.kt @ExperimentalCoroutinesApi public actual fun CoroutineScope.newCoroutineContext(context: CoroutineContext): CoroutineContext { val combined = coroutineContext + context val debug = if (DEBUG) combined + CoroutineId(COROUTINE_ID.incrementAndGet()) else combined return if (combined !== Dispatchers.Default && combined[ContinuationInterceptor] == null) debug + Dispatchers.Default else debug } 
 // Dispatchers.kt public actual val Default: CoroutineDispatcher = createDefaultDispatcher() // CoroutineContext.kt internal actual fun createDefaultDispatcher(): CoroutineDispatcher = if (useCoroutinesScheduler) DefaultScheduler else CommonPool Dispatchers.DefaultΛ࡞Δ CommonPoolΛ࡞Δ

Slide 7

Slide 7 text

CommonPoolΛ࡞Δ // CommonPool.kt override val executor: Executor get() = pool ?: getOrCreatePoolSync() @Volatile private var pool: Executor? = null @Synchronized private fun getOrCreatePoolSync(): Executor = pool ?: createPool().also { pool = it } private fun createPool(): ExecutorService { if (System.getSecurityManager() != null) return createPlainPool() // Reflection on ForkJoinPool class so that it works on JDK 6 (which is absent there) val fjpClass = Try { Class.forName("java.util.concurrent.ForkJoinPool") } ?: return createPlainPool() // Fallback to plain thread pool // Try to use commonPool unless parallelism was explicitly specified or in debug privatePool mode if (!usePrivatePool && requestedParallelism < 0) { Try { fjpClass.getMethod("commonPool")?.invoke(null) as? ExecutorService } ?.takeIf { isGoodCommonPool(fjpClass, it) } ?.let { return it } } // Try to create private ForkJoinPool instance Try { fjpClass.getConstructor(Int::class.java).newInstance(parallelism) as? ExecutorService } ?. let { return it } // Fallback to plain thread pool return createPlainPool() } pool͕nullͳΒCreatePoolSyncΛ࡞Δ pool͕nullͳΒCreatePool createPlainPool͢ΔͱExecutorServiceΛ࡞Δ

Slide 8

Slide 8 text

createPlainPool()? private fun createPlainPool(): ExecutorService { val threadId = AtomicInteger() return Executors.newFixedThreadPool(parallelism) { Thread(it, "CommonPool-worker-$ {threadId.incrementAndGet()}").apply { isDaemon = true } } } public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), threadFactory); } ʂʂʂ ʂʂʂʂʂ

Slide 9

Slide 9 text

εϨου࡞ͬͯΔʂ

Slide 10

Slide 10 text

ͳͥCoroutine͸ܰྔతʁ

Slide 11

Slide 11 text

ಛఆͷॲཧΛ଴͍ͪͨͱ͖

Slide 12

Slide 12 text

delayؔ਺

Slide 13

Slide 13 text

• Thread : Thread.sleep(long)
 - ࢦఆͨ࣌ؒ͠ͷ௕͞ʹΘͨͬͯݱࡏͷεϨο υΛதஅ͠·͢ • Coroutine : delay(long)
 - Coroutine಺ͷॲཧΛࢦఆͨ࣌ؒ͠ͷ௕͞ʹ Θͨͬͯதஅ͢Δ
 - suspending function(தஅؔ਺)

Slide 14

Slide 14 text

delayΛݺͿ // Delay.kt public suspend fun delay(timeMillis: Long) { if (timeMillis <= 0) return // don't delay return suspendCancellableCoroutine sc@ { cont: CancellableContinuation -> cont.context.delay.scheduleResumeAfterDelay(timeMillis, cont) } } // Executors.kt override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation) { val future = if (removesFutureOnCancellation) { scheduleBlock(ResumeUndispatchedRunnable(this, continuation), timeMillis, TimeUnit.MILLISECONDS) } else { null } // If everything went fine and the scheduling attempt was not rejected -- use it if (future != null) { continuation.cancelFutureOnCancellation(future) return } // Otherwise fallback to default executor DefaultExecutor.scheduleResumeAfterDelay(timeMillis, continuation) }

Slide 15

Slide 15 text

scheduleΛBlock // Executors.kt private fun scheduleBlock(block: Runnable, time: Long, unit: TimeUnit): ScheduledFuture<*>? { return try { (executor as? ScheduledExecutorService)?.schedule(block, time, unit) } catch (e: RejectedExecutionException) { null } }

Slide 16

Slide 16 text

ScheduledExecutorService

Slide 17

Slide 17 text

લճͷษڧձͰ΋গ͠৮Εͨ ؾ͕͢Δ

Slide 18

Slide 18 text

• ThreadΫϥε
 - ࠷΋جຊతͳεϨουੜ੒ɾىಈͷΫϥε • RunnableΠϯλʔϑΣʔε
 - εϨου͕࣮ߦ͢Δʮ࢓ࣄʯΛද͢ΠϯλʔϑΣʔε • ThreadFactoryΠϯλʔϑΣʔε
 - εϨουੜ੒Λந৅Խͨ͠ΠϯλʔϑΣʔε • ExecutorΠϯλʔϑΣʔε
 - εϨουͷ࣮ߦΛந৅Խͨ͠ΠϯλʔϑΣʔε • ExecutorServiceΠϯλʔϑΣʔε
 - ࠶ར༻͞ΕΔεϨουͷ࣮ߦΛந৅Խͨ͠ΠϯλʔϑΣʔε • ScheduledExecutorServiceΠϯλʔϑΣʔε
 - εέδϡʔϦϯά͞ΕͨεϨουͷ࣮ߦΛந৅Խͨ͠ΠϯλʔϑΣʔε • ExecutorsΫϥε
 - Πϯελϯεੜ੒ͷϢʔςΟϦςΟΫϥε

Slide 19

Slide 19 text

͋ͬͨʂ • ExecutorServiceΠϯλʔϑΣʔε
 - ࠶ར༻͞ΕΔεϨουͷ࣮ߦΛந৅Խͨ͠Π ϯλʔϑΣʔε • ScheduledExecutorServiceΠϯλʔϑΣʔε
 - εέδϡʔϦϯά͞ΕͨεϨουͷ࣮ߦΛந ৅Խͨ͠ΠϯλʔϑΣʔε

Slide 20

Slide 20 text

ͭ·ΓDelay΋ɺɺɺ

Slide 21

Slide 21 text

Threadܥͷॲཧɻ͞Βʹɺ

Slide 22

Slide 22 text

εέδϡʔϦϯάͰ͖Δ ࠶ར༻Մೳͳ εϨουΛ ࢖͍·Θ͍ͯ͠Δ

Slide 23

Slide 23 text

• Thread : Thread.sleep(long)
 - εϨουͦͷ΋ͷΛࢭΊ͍ͯΔ • Coroutine : delay(long)
 - ࠶ར༻ՄೳͳεϨουΛ࢖͍·Θͯ࣍͠ͷॲ ཧΛεέδϡʔϦϯά͍ͯ͠Δ

Slide 24

Slide 24 text

͔֬ʹ͍ܰ

Slide 25

Slide 25 text

Fin.

Slide 26

Slide 26 text

ࢀߟࢿྉ • https://qiita.com/takahirom/items/ 2ba221a8d0c32cf701ba • https://qiita.com/pljp/items/ 768f26bc09913f60dd07 • https://speakerdeck.com/takahirom