package com.lee.kotlin.coroutine

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.actor
import kotlin.system.measureTimeMillis


suspend fun massiveRun(action: suspend () -> Unit) {
    val n = 100  // 启动的协程数量
    val k = 1000 // 每个协程重复执行同一动作的次数
    val time = measureTimeMillis {
        coroutineScope { // 协程的作用域
            repeat(n) {
                launch {
                    repeat(k) { action() }
                }
            }
        }
    }
    println("Completed ${n * k} actions in $time ms")
}

// 共享的可变状态与并发
//// volatile 无济于事
//// volatile 变量保证可线性化（这是“原子”的技术术语）读取和写入变量，
//// 但在大量动作（在我们的示例中即“递增”操作）发生时并不提供原子性
//@Volatile // 在 Kotlin 中 `volatile` 是一个注解
//var counter = 0
//
//// 它不太可能打印出“Counter = 100000”，因为一百个协程在多个线程中同时递增计数器但没有做并发处理。
//fun main() = runBlocking {
//    withContext(Dispatchers.Default) {
//        massiveRun {
//            counter++
//        }
//    }
//    println("Counter = $counter")
//}

// 线程安全的数据结构
//var counter = AtomicInteger()
//
//fun main() = runBlocking {
//    withContext(Dispatchers.Default) {
//        massiveRun {
//            counter.incrementAndGet()
//        }
//    }
//    println("Counter = $counter")
//}

// 以细粒度限制线程
// 限制线程 是解决共享可变状态问题的一种方案：对特定共享状态的所有访问权都限制在单个线程中。
//val counterContext = newSingleThreadContext("CounterContext")
//var counter = 0
//
//fun main() = runBlocking {
//    withContext(Dispatchers.Default) {
//        massiveRun {
//            // 将每次自增限制在单线程上下文中
//            withContext(counterContext) {
//                counter++
//            }
//        }
//    }
//    println("Counter = $counter")
//}

// 以粗粒度限制线程
//val counterContext = newSingleThreadContext("CounterContext")
//var counter = 0
//
//fun main() = runBlocking {
//    // 将一切都限制在单线程上下文中
//    withContext(counterContext) {
//        massiveRun {
//            counter++
//        }
//    }
//    println("Counter = $counter")
//}

// 互斥
// 通常会为此目的使用 synchronized 或者 ReentrantLock。 在协程中的替代品叫做 Mutex 。
// 它具有 lock 和 unlock 方法， 可以隔离关键的部分。
// 关键的区别在于 Mutex.lock() 是一个挂起函数，它不会阻塞线程。
//val mutex = Mutex()
//var counter = 0
//
//fun main() = runBlocking {
//    withContext(Dispatchers.Default) {
//        massiveRun {
//            // 用锁保护每次自增
//            mutex.withLock {
//                counter++
//            }
//        }
//    }
//    println("Counter = $counter")
//}

// Actors
//一个 actor 是由协程、 被限制并封装到该协程中的状态以及一个与其它协程通信的 通道 组合而成的一个实体。
// 一个简单的 actor 可以简单的写成一个函数， 但是一个拥有复杂状态的 actor 更适合由类来表示。

// 计数器 Actor 的各种类型
sealed class CounterMsg
object IncCounter : CounterMsg() // 递增计数器的单向消息
class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg() // 携带回复的请求

// 这个函数启动一个新的计数器 actor
fun CoroutineScope.counterActor() = actor<CounterMsg> {
    var counter = 0 // actor 状态
    for (msg in channel) { // 即将到来消息的迭代器
        when (msg) {
            is IncCounter -> counter++
            is GetCounter -> msg.response.complete(counter)
        }
    }
}

fun main() = runBlocking<Unit> {
    val counter = counterActor() // 创建该 actor
    withContext(Dispatchers.Default) {
        massiveRun {
            counter.send(IncCounter)
        }
    }
    // 发送一条消息以用来从一个 actor 中获取计数值
    val response = CompletableDeferred<Int>()
    counter.send(GetCounter(response))
    println("Counter = ${response.await()}")
    counter.close() // 关闭该actor
}



