Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import kotlinx.coroutines.*
- import kotlinx.coroutines.channels.BroadcastChannel
- import kotlinx.coroutines.channels.broadcast
- import kotlinx.coroutines.sync.Mutex
- import kotlinx.coroutines.sync.withLock
- import kotlin.coroutines.CoroutineContext
- class View(ui: CoroutineContext) {
- private val presenter = Presenter(
- ui = ui,
- io = Dispatchers.IO,
- view = this,
- interactor = Interactor()
- )
- fun process(id: Int, value: Int) {
- presenter.given(id, value)
- }
- fun render(id: Int, result: Int) {
- println("call[$id]view result: $result")
- }
- fun render(id: Int, e: Throwable) {
- println("call[$id]view error: $e")
- throw e
- }
- }
- class Interactor {
- private var count: Int = 0
- suspend fun doSomething(value : Int): Int{
- println("interactor: ${++count}")
- delay(50)
- return value * value
- }
- }
- data class HotInvocationContext(
- val mutex: Mutex = Mutex(),
- val map: MutableMap<String, BroadcastChannel<*>> = mutableMapOf()
- )
- suspend fun <T> CoroutineScope.invokeHot(
- set: HotInvocationContext,
- key: String,
- block: suspend () -> T
- ): T {
- val (mutex, map) = set
- return mutex.withLock {
- if (map.contains(key)) {
- if (!map[key]!!.isClosedForSend) {
- println("channel reused")
- val broadcastChannel = map[key] as BroadcastChannel<T>
- return@withLock broadcastChannel.openSubscription()
- } else {
- println("channel has been closed")
- map.remove(key)
- }
- }
- println("channel created")
- val broadcastChannel = map.getOrPut(key) {
- broadcast {
- val result = block()
- mutex.withLock {
- send(result)
- map.remove(key)
- }
- println("channel sent")
- }
- } as BroadcastChannel<T>
- broadcastChannel.openSubscription()
- }.receive()
- }
- class Presenter(
- ui: CoroutineContext,
- private val io: CoroutineDispatcher,
- private val view: View,
- private val interactor: Interactor
- ): CoroutineScope {
- private val set: HotInvocationContext = HotInvocationContext()
- private val job: Job = Job()
- override val coroutineContext: CoroutineContext = job + ui
- fun given(id: Int, value: Int) {
- launch {
- runCatching {
- withContext(io) {
- invokeHot(set, "doSomething$value") {
- interactor.doSomething(value)
- }
- }
- }
- .onSuccess { view.render(id, it) }
- .onFailure { view.render(id, it) }
- }
- }
- }
- fun main() = runBlocking {
- val view = View(coroutineContext)
- repeat(10000) {
- delay(10)
- println("call[$it]")
- view.process(it, 5)
- }
- }
Add Comment
Please, Sign In to add comment