Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Nativeにおけるfrozen状態と並行処理について

Kotlin Nativeにおけるfrozen状態と並行処理について

Flutter × Kotlin Multiplatform by CyberAgent #2の登壇資料です。

2793f1fe246c9299c2416062d22bfb99?s=128

Sato Shun

March 02, 2021
Tweet

Transcript

  1. Sato Shun Tapple, inc. Kotlin Nativeͷfrozenͱ ฒߦॲཧʹ͍ͭͯ

  2. લఏ஌ࣝ • ଟগͷKotlinͷ஌ࣝ

  3. ໨࣍ • ͦ΋ͦ΋ͷฒߦॲཧͷ೉͍͠ॴ • Kotlin NativeͰ͸ͲͷΑ͏ʹͯ͠ɺ͜ͷ՝୊Λղܾ͔ͨ͠ • Kotlin Nativeͷฒߦॲཧ

  4. ฒߦॲཧͷ೉͍͠ॴ • mutableͳΠϯελϯεΛෳ਺εϨου͔Βૢ࡞͢Δ࣌ • synchronized΍ɺmutexͳͲͷϩοΫΛ࢖͏ • AtomicܥͷAPIΛ࢖͏ • બ୒ࢶ΋ଟ͘ɺద੾ʹॻ͘͜ͱ͸೉͍͠ •

    ·ͨόά͕ى͖ͨ࣌ʹ࠶ݱੑ͕௿͘ɺݪҼͷಛఆ͕ࠔ೉
  5. ฒߦॲཧͷ೉͍͠ॴ • ͦ͜ͰKotlin NativeʢiOSଆʣͰ͸ɺmutableͳঢ়ଶͷΠϯελϯεʹର͠ ͯɺͱ͋Δ੍໿Λઃ͚Δ͜ͱͰղܾΛ໨ࢦͨ͠

  6. shared XOR mutable੍໿ • ฒߦॲཧͰ໰୊͕ग़Δɺshared ͔ͭ mutableͳঢ়ଶΛڐՄ͠ͳ͍ͱ͍͏੍ ໿ • RustͳͲͰ΋࢖ΘΕ͍ͯΔ੍໿ʢΒ͍͠ʣ

    • ͜ͷ੍໿Λຬͨͨ͢ΊʹɺKotlin NativeͰ͸ frozenঢ়ଶ Λಋೖͨ͠
  7. frozenঢ়ଶ? • ͦͷΠϯελϯε͕immutableͰ͋Δ͜ͱΛอূ͢Δ

  8. frozenঢ়ଶ? • ͦͷΠϯελϯε͕immutableͰ͋Δ͜ͱΛอূ͢Δ /** * Freezes object subgraph reachable from

    this object. Frozen objects can be freely * shared between threads/workers. * * @throws FreezingException if freezing is not possible * @return the object itself * @see ensureNeverFrozen */ public fun <T> T.freeze(): T
  9. frozenঢ়ଶ? • ͦͷΠϯελϯε͕immutableͰ͋Δ͜ͱΛอূ͢Δ • freezeͨ͠ΠϯελϯεΛมߋ͠Α͏ͱ͢ΔͱɺΫϥογϡ͢Δ • ଞͷεϨουͱ҆શʹڞ༗͢Δ͜ͱ͕ग़དྷΔ

  10. frozenঢ়ଶ? • ͦͷΠϯελϯε͕immutableͰ͋Δ͜ͱΛอূ͢Δ • freezeͨ͠ΠϯελϯεΛมߋ͠Α͏ͱ͢ΔͱɺΫϥογϡ͢Δ • ଞͷεϨουͱ҆શʹڞ༗͢Δ͜ͱ͕ग़དྷΔ /** * Checks

    if given object is null or frozen or permanent (i.e. instantiated at compile-time). * * @return true if given object is null or frozen or permanent */ public val Any ?. isFrozen
  11. frozenঢ়ଶ? • ͦͷΠϯελϯε͕immutableͰ͋Δ͜ͱΛอূ͢Δ • freezeͨ͠ΠϯελϯεΛมߋ͠Α͏ͱ͢ΔͱɺΫϥογϡ͢Δ • ଞͷεϨουͱ҆શʹڞ༗͢Δ͜ͱ͕ग़དྷΔ • unfreeze͸ଘࡏ͠ͳ͍

  12. val sample = Sample(3) sample.i + + sample.freeze() sample.i +

    +
  13. val sample = Sample(3) sample.i + + sample.freeze() sample.i +

    + Uncaught Kotlin exception: kotlin.native.concurrent.InvalidMutabilityException
  14. KMMͷfrozenͷ໰୊఺ • JVM(Android)ͱNative(iOS)Ͱڍಈ͕ҟͳΔ • JVMʹ͸frozenঢ়ଶͱ͍͏֓೦͸ͳ͍ • AndroidͰ͸ಈ͘ɺ͔͠͠iOSͰ͸Ϋϥογϡ͢ΔɻΈ͍ͨͳ͜ͱ͕ى͜ ΔՄೳੑ͕͋Δ • ·ͨɺKotlin

    NativeͰ͸freezeΛ໌ࣔతʹݺ͹ͳͯ͘΋ɺ҉໧తʹfreeze͠ ͯ͠·͏ύλʔϯ͕͋Δ
  15. ҉໧తͳfreeze • objectɺcompanion objectͳͲ͸ɺࣗಈͰfreeze͢Δ࢓༷ʹͳ͍ͬͯΔ

  16. object DefaultGlobalState { private var i = 5 fun countUp()

    { i ++ } }
  17. object DefaultGlobalState { private var i = 5 fun countUp()

    { i ++ } } Uncaught Kotlin exception: kotlin.native.concurrent.InvalidMutabilityException
  18. @ThreadLocal object DefaultGlobalState { private var i = 5 fun

    countUp() { i ++ } }
  19. ͜͜·Ͱͷ·ͱΊ • shared XOR mutableΛຬͨͨ͢Ίʹfrozen͕ಋೖ͞Εͨ • frozenঢ়ଶʹ͢Δ͜ͱͰɺimmutableͳঢ়ଶΛදݱͰ͖Δ • ͜Ε͸ฒྻॲཧΛ҆શʹѻ͏͜ͱ͕ग़དྷΔ •

    ͔͠͠ɺ҉໧తͳfrozenͳͲͰɺiOS͚ͩಈ͔ͳ͍Մೳੑ͕͋Δ
  20. Kotlin Nativeͷฒߦॲཧ • ௿ϨϕϧAPIͱͯ͠ɺWorkerΫϥε͕༻ҙ͞Ε͍ͯΔ • JavaͰ͍͏ͱ͜ΖͷThreadΫϥε • Kotlin NativeͰ͸ɺجຊతʹεϨου͕มΘΔ৔߹ɺfrozenঢ়ଶʹͯ͠ immutableʹ͢Δඞཁ͕͋Δ

  21. val worker = Worker.start() worker.execute(TransferMode.SAFE, { … }) { …

    }
  22. val worker = Worker.start() worker.execute(TransferMode.SAFE, { … }) { …

    } public fun <T1, T2> execute( mode: TransferMode, producer: () -> T1, @VolatileLambda job: (T1) - > T2 ): Future<T2>
  23. data class Sample(var i: Int) val sample = Sample(1)

  24. data class Sample(var i: Int) val sample = Sample(1) worker.execute(TransferMode.SAFE,

    { sample }) { println(it) }
  25. data class Sample(var i: Int) val sample = Sample(1) worker.execute(TransferMode.SAFE,

    { sample }) { println(it) } Uncaught Kotlin exception: kotlin.IllegalStateException: Illegal transfer state
  26. data class Sample(var i: Int) val sample = Sample(1) worker.execute(TransferMode.SAFE,

    { sample.freeze() }) { println(it) }
  27. data class Sample(var i: Int) val sample = Sample(1) val

    sample2 = Sample(2)
  28. data class Sample(var i: Int) val sample = Sample(1) val

    sample2 = Sample(2) worker.execute(TransferMode.SAFE, { sample.freeze() }) { println(it) }
  29. data class Sample(var i: Int) val sample = Sample(1) val

    sample2 = Sample(2) fun background(block: () -> Unit) { worker.execute(TransferMode.SAFE, { block.freeze() }) { it() } }
  30. data class Sample(var i: Int) val sample = Sample(1) val

    sample2 = Sample(2) background { println(sample) println(sample2) } fun background(block: () -> Unit) { worker.execute(TransferMode.SAFE, { block.freeze() }) { it() } }
  31. data class Sample(var i: Int) val sample = Sample(1) val

    sample2 = Sample(2) background { println(sample) println(sample2) } fun background(block: () -> Unit) { worker.execute(TransferMode.SAFE, { block.freeze() }) { it() } } sampleɺsample2ຊମΛfreeze͍ͯ͠ͳ͍ εϨου͕มΘΔ৔߹͸ɺfreeze͠ͳ͍ͱ͍͚ͳ͍ͷͰ͸?
  32. data class Sample(var i: Int) val sample = Sample(1) val

    sample2 = Sample(2) background { println(sample) println(sample2) } fun background(block: () -> Unit) { worker.execute(TransferMode.SAFE, { block.freeze() }) { it() } } sampleɺsample2ຊମΛfreeze͍ͯ͠ͳ͍ εϨου͕มΘΔ৔߹͸ɺfreeze͠ͳ͍ͱ͍͚ͳ͍ͷͰ͸? ϥϜμຊମΛfreeze͢Δͱɺ ͦͷϥϜμ͕ࢀর͍ͯ͠Δม਺΋࿈࠯తʹfreeze͞ΕΔ
  33. Kotlin Nativeͷฒߦॲཧͷ·ͱΊ • Kotlin Nativeʹ͸Workerͱ͍͏௿ϨϕϧAPI͕༻ҙ͞Ε͍ͯΔ • εϨουؒΛލ͙ͱ͖͸ɺfreeze͢Δඞཁ͕͋Δ • ͋ΔΠϯελϯεΛfreeze͢Δͱɺࢀর͞Ε͍ͯΔΠϯελϯε΋࿈࠯త ʹfreeze͢Δ

  34. ͓·͚: Coroutineʹ͍ͭͯ • ࣮ࡍͷ։ൃͰ͸ɺCoroutineͳͲͷߴϨϕϧͳAPIΛ࢖͏͜ͱ͕ଟ͍ • ݱঢ়ɺKotlin Nativeʹ͓͚ΔCoroutine͸ʮ୯ҰεϨουʹͷΈରԠͨ͠௨ ৗόʔδϣϯʯͱʮෳ਺εϨουʹରԠͨ͠όʔδϣϯʯ͕͋Δ

  35. val sample = Sample("1") println(sample.isFrozen) withContext(Dispatchers.Default) { println(sample.isFrozen) }

  36. val sample = Sample("1") println(sample.isFrozen) withContext(Dispatchers.Default) { println(sample.isFrozen) } ୯ҰεϨουόʔδϣϯͷCoroutineͷ৔߹͸ɺisFrozen͸falseɺ

    ෳ਺εϨουόʔδϣϯͷCoroutineͷ৔߹͸ɺisFrozen͸true
  37. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠