Created
September 4, 2020 17:45
-
-
Save chimerast/6a1941a7d9b4387f661a03b7478db2f7 to your computer and use it in GitHub Desktop.
Coroutineの説明用に作って見た
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package example | |
import kotlinx.coroutines.* | |
import java.util.concurrent.Executors | |
import java.util.concurrent.TimeUnit | |
import java.util.concurrent.atomic.AtomicInteger | |
fun main() { | |
val nCount = 100000 | |
useCoroutine(1) { unsafe(this, nCount) }.also { println() } | |
useCoroutine(10) { unsafe(this, nCount) }.also { println() } | |
useCoroutine(1) { maybeUnsafe(this, nCount) }.also { println() } | |
useCoroutine(10) { maybeUnsafe(this, nCount) }.also { println() } | |
useCoroutine(1) { safe(this, nCount) }.also { println() } | |
useCoroutine(10) { safe(this, nCount) }.also { println() } | |
ThreadName.printActives() | |
} | |
fun useCoroutine(nThreads: Int, block: suspend CoroutineScope.() -> Unit) { | |
val pool = Executors.newFixedThreadPool(nThreads) | |
pool.asCoroutineDispatcher().use { | |
runBlocking(it) { | |
block() | |
} | |
} | |
pool.awaitTermination(10, TimeUnit.MINUTES) | |
} | |
suspend fun unsafe(scope: CoroutineScope, nCount: Int) { | |
ThreadName.printCurrent() | |
var counter = 0 | |
List(nCount) { | |
scope.async { | |
counter++ | |
} | |
}.awaitAll() | |
println("total counter: $counter") | |
} | |
suspend fun maybeUnsafe(scope: CoroutineScope, nCount: Int) { | |
ThreadName.printCurrent() | |
val lock = Object() | |
var counter = 0 | |
List(nCount) { | |
scope.async { | |
// lockというインスタンスで、critical sectionを作り上げているが、 | |
// スレッド間でCPUレジスタレベルでデータの同期が取れているのは、lockとその内包するattributeだけで、 | |
// counterは実はデータ同期の対象外、まあ、これくらいなら動くけど、いつ死ぬかはわからない | |
synchronized(lock) { | |
counter++ | |
} | |
} | |
}.awaitAll() | |
println("total counter: $counter") | |
} | |
suspend fun safe(scope: CoroutineScope, nCount: Int) { | |
ThreadName.printCurrent() | |
val counter = AtomicInteger(0) | |
List(nCount) { | |
scope.async { | |
counter.getAndIncrement() | |
} | |
}.awaitAll() | |
println("total counter: $counter") | |
} | |
object ThreadName { | |
fun printCurrent() { | |
println(Thread.currentThread().name) | |
} | |
fun printActives() { | |
val threads = arrayOfNulls<Thread>(Thread.activeCount()) | |
Thread.enumerate(threads) | |
threads.mapNotNull { it?.name }.forEach { println(it) } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
一旦挙動のチェックとして。一部作って見た。サチったときの挙動をどう再現するかが難しい。