@file:Suppress("UNREACHABLE_CODE")
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.Default
import kotlinx.coroutines.channels.*
import kotlinx.coroutines.channels.Channel.Factory.BUFFERED
import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.selects.select
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import sun.rmi.server.Dispatcher
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
import kotlin.coroutines.suspendCoroutine
import kotlin.system.measureTimeMillis

fun main() {
//    coroutineBuilder()
//    coroutineScopeExample()
   // jobFunctions()
//    suspendFunctions()
  //  channelExanple()
      flowExample()
//    yieldFun()
   // coroutineException()
//    selectClause()
    mutableState()
}

//只有下列五个函数中可以调用挂起函数
fun coroutineBuilder() {
    println("---------------------------Coroutine Builder------------------------")
    //launch，由CoroutineScope对象调用，生成job，可据此cancel
    buildCoroutineScope(1).launch {    // 在后台启动一个新的协程并继续
        delay(1000L)                // 非阻塞的等待 1 秒钟（默认时间单位是毫秒）
        println("World!")                   // 在延迟后打印输出
    }
    print("launch: Hello,")                       // 协程已在等待时主线程还在继续
    Thread.sleep(2000L)               // 阻塞主线程 2 秒钟来保证 JVM 存活

    //async，由CoroutineScope对象调用，生成job的子类deffered，可据此cancel和获取结果（deffered.await()）
    val asyncResult = buildCoroutineScope(1).async {    // 在后台启动一个新的协程并继续
        doSomethingOne()
    }
    buildCoroutineScope(1).launch {
        println("async result:${asyncResult.await()}")                   // 协程已在等待时主线程还在继续
    }
    Thread.sleep(2000L)

    //runBlocking,直接在调用（无需其它对象）,阻塞当前线程，直到协程中的任务结束
    runBlocking(Default) {
        doSomething()
    }

    //produce，由CoroutineScope对象调用，


    //broadcast


}

fun coroutineScopeExample() {
    println("---------------------------Coroutine Scope------------------------")
    runBlocking {
        for (i in 1..7) {
            print("$i:")
            when (i) {
                1 -> print("GlobalScope:")
                2 -> print("CoroutineScope(Dispatchers.Default):")
                3 -> print("CoroutineScope(Dispatchers.Unconfined):")
                4 -> print("CoroutineScope(Dispatchers.IO):")
                5 -> print("CoroutineScope(newSingleThreadContext('MyThread')):")
                6 -> print("CoroutineScope(newFixedThreadPoolContext(5,'MyThreadPool')):")
                7 -> print("MyCroutineScope():")
                else -> print("MainScope()/CoroutineScope(Dispatchers.Main):")
            }
            val job = buildCoroutineScope(i).launch {
                doSomething()
            }
            job.join()
        }
        delay(2000)
    }
}

fun jobFunctions() {
    println("--------------------------Job Function------------------------")
    runBlocking {
        joinFun()
        cancelFun()
        awaitFun()
        startFun()
        supervisorJobFun()
    }
}

//子协程发生异常我们并不希望父协程也被取消, 而是仅仅所有子协程取消；父协程取消以后该子协程依然处于活跃状态
//在withContext和async中添加无效，仅适用于launch（launch(SupervisorJob()) {  }）
suspend fun supervisorJobFun() {
    println("--------SupervisorJob------------")
    val supervisor = SupervisorJob()
    with(CoroutineScope(coroutineContext + supervisor)) {
        // 启动第一个子作业——这个示例将会忽略它的异常（不要在实践中这么做！）
        val firstChild = launch(CoroutineExceptionHandler { _, _ -> }) {
            println("First child is failing")
            throw AssertionError("First child is cancelled")
        }
        // 启动第二个子作业
        val secondChild = launch {
            firstChild.join()
            // 取消了第一个子作业且没有传播给第二个子作业
            println("First child is cancelled: ${firstChild.isCancelled}, but second one is still active")
            try {
                delay(Long.MAX_VALUE)
            } finally {
                // 但是取消了监督的传播
                println("Second child is cancelled because supervisor is cancelled")
            }
        }
        // 等待直到第一个子作业失败或执行完成
        firstChild.join()
        //取消supervisorJob，导致其内所有子作业取消
        println("Cancelling supervisor")
        supervisor.cancel()
        secondChild.join()
    }
}
//join：等待设置了isActive=false的协程执行完成
suspend fun joinFun() = coroutineScope {
    println("--------job join------------")
    val job = launch(Dispatchers.Default) {
        delay(1000L)
        println("World!")
    }
    print("Hello,")
    job.join()
    println("子协程执行结束")
}

//cancel：1）状态的转移，isActive = false，并不会取消协程的实际运算逻辑  2）处理回调：通知各个观察者（订阅者）
//job.join之前调用 job.cancel，那么协程会在任务处理完成之前一直处于挂起状态；job.join 之后调用 job.cancel 没有什么影响，因为 job 已经完成了。
suspend fun cancelFun() = coroutineScope {
    println("--------job cancel------------")

    val job1 = launch(Dispatchers.Default) {
        repeat(5) {
            println("job1 sleep ${it + 1} times")
            //delay()会检测协程是否已取消，协程库中很多挂起函数都会检测协程状态
            delay(500)
        }
    }
    delay(700)
    job1.cancel()

    val startTime = System.currentTimeMillis()
    val job2 = launch(Dispatchers.Default) {
        var nextPrintTime = startTime
        var i = 0
        //while (i <= 5) { //不能取消
        //ensureActive()   //相当于isActive，非活跃状态时会立即抛出异常
        while (isActive) { //可以取消
            if (System.currentTimeMillis() >= nextPrintTime) {
                println("job2: I'm sleeping ${i++} ...")
                nextPrintTime += 500L
            }
        }
        println("job2: After sleeping...")
    }
    delay(1300L) // delay a bit
    println("main: I'm tired of waiting!")
    job2.cancel() // 不会等待耗时循环体后面的代码执行完成
    //job2.cancelAndJoin()   //会等待耗时循环体后面的代码执行完成
    println("main: Now I can quit.")

    //cancel时，协程中有挂起函数才会抛异常CancellationException,子协程因此而被取消时，它的父协程不需要进行额外操作，也不影响其兄弟协程
        val job3 = launch(Default) {
            println("job3-----1")
            try {
                //isActive配合才能取消，此时不会抛异常
                while (isActive) {
                    print(".")
                    //或者使用挂起函数来取消，此时会抛异常
                    //delay(10)
              }

                println("job3-----2")
            }
             catch (e: Exception) {
                println("job3 Caught: $e")
            }finally {
                println("job3: I'm running finally")
            }
        }
        delay(100)
        println("job3-----3")
        job3.cancel()
        println("job3-----4")


    val job4 = launch {
        try {
            repeat(1000) { i ->
                println("job4: I'm sleeping $i ...")
                delay(500L)
            }
        } finally {
            withContext(NonCancellable) {   //通常在此处进行清理工作，如果不是NonCancellable，则可能不执行不到
                println("job4: I'm running finally")
                delay(1000L)
                println("job4: And I've just delayed for 1 sec because I'm non-cancellable")
            }
        }
    }
    delay(1300L) // delay a bit
    println("main: I'm tired of waiting!")
    job4.cancelAndJoin() // cancels the job and waits for its completion
    println("main: Now I can quit.")
}

suspend fun awaitFun() = coroutineScope {
    println("--------deffered await------------")
    val time = measureTimeMillis {//系统函数统计时间
        val one = async { doSomethingOne() }//异步调用，返回结果
        val two = async { doSomethingTwo() }
        println("The answer is ${one.await() + two.await()}")//等待异步执行完成（await调用会挂起当前线程,等待执行结果完成后，通过调用resume恢复挂起前状态）
    }
    println("Completed in $time ms")
}

suspend fun startFun() = coroutineScope {
    println("--------job start------------")

    val job = launch(start = CoroutineStart.LAZY) { doSomething() }
    delay(3000)
    println("job not started ")
    job.start()
    job.join()
    println("job finished!")
}

//同步作用域函数
fun suspendFunctions() {
    println("--------------------------suspend Function------------------------")
    coroutineScopeFun()         //创建一个协程作用域, 该作用域会阻塞当前所在作用域并且等待其子协程执行完才会恢复, 有返回结果
    supervisorScopeFun()        //使用SupervisorJob的coroutineScope, 异常不会取消父协程
    withContextFun()            //可以切换调度器, 有返回结果
    withTimeoutFun()
    withTimeoutOrNullFun()
}

fun coroutineScopeFun() = runBlocking {
    println("--------coroutineScope------------")
    coroutineScope() {
        doSomething()
    }
}

//可解决superviosrJob生命周期不统一问题, 创建向下传播异常的协程作用域
fun supervisorScopeFun() = runBlocking(Dispatchers.IO) {
    println("--------supervisorScope------------")
    val handler = CoroutineExceptionHandler { _, exception ->
        println("CoroutineExceptionHandler got $exception")
    }
    try {
        supervisorScope() {
            println("Scope is starting")
            val child1 = launch() {
                try {
                    println("Child1 is starting")
                    delay(5000)
                    println("Child1 is awaking")

                } catch (e: Exception) {
                    println("Child1 throw excepyion:${e.message}")
                } finally {
                    println("Child1 is finshed")
                }
            }

            val child2 = launch(handler) {
                println("Child2 is starting")
                delay(1000)
                println("Child2 throws an exception")
                throw AssertionError()
            }
            delay(2000)
            println("child1 is canceling")
            child1.cancel()
//          println("Scope throws an exception")
//          throw ArithmeticException()
            println("Scope is completing")
        }
    } catch (e: ArithmeticException) {
        println("Caught ArithmeticException ")
    }
    println("Scope is completed")
}

fun withContextFun() = runBlocking {
    println("--------withContext------------")
    val backgroundThread = newSingleThreadContext("Background Thread")
    withContext(backgroundThread) {
        doSomething()
    }
}

fun withTimeoutFun() = runBlocking() {
    println("--------withTimeout------------")
    try {
        withTimeout(1300L) {
            repeat(1000) { i ->
                println("I'm sleeping $i ...")
                delay(500L)
            }
        }
    } catch (e: TimeoutCancellationException) {
        println("Time out")
    }
}

fun withTimeoutOrNullFun() = runBlocking {
    println("--------withTimeoutOrNull------------")
    val result = withTimeoutOrNull(1300L) {
        repeat(10) { i ->
            println("I'm sleeping $i ...")
            delay(500L)
        }
        "Done"      // will get cancelled before it produces this result
    }
    println("Result is $result")
}

//协程coroutines 调用的方法需要用suspend修饰，告诉编译器此函数可以被挂起
suspend fun doSomething() {
    delay(2000L)
    println("Do something for 2 second in ${Thread.currentThread().name}")
}

suspend fun doSomethingOne(): Int {
    delay(1000L)
    return 13
}

suspend fun doSomethingTwo(): Int {
    delay(2000L)
    return 29
}

fun ReceiveChannel<Int>.sqrt(): ReceiveChannel<Double> = GlobalScope.produce(Dispatchers.Unconfined) {
    for (number in 1..10) {
        send(Math.sqrt(number.toDouble()))
    }
}

fun flowExample() {
    println("--------flow Basic------------")
    fun simple(): Flow<Int> = flow {// 流构建器
        println("Flow started")
        for (i in 1..3) {
            delay(100)   // 假装我们在这里做了一些有用的事情
            println("emitting: $i......")
            emit(i)               // 发送下一个值
        }
    }
    //异步返回每个值
        runBlocking<Unit> {
                // 启动并发的协程以验证主线程并未阻塞
                launch {
                    for (k in 1..3) {
                        println("I'm not blocked $k")
                        delay(100)
                    }
                }
                // 收集这个流
                simple().collect { println("collecting: $it!") }
            }
    //Flow是一种类似于序列的冷流,直到流被收集的时候才运行,每收集一次就运行一次
    runBlocking<Unit> {
        println("Calling simple function...")
        val flow = simple()
        println("Calling collect...")
        flow.collect { value -> println(value) }
        println("Calling collect again...")
        flow.collect { value -> println("collecting $value") }

    }

    //流是连续的,上游到下游每个过渡操作符都会处理每个发射出的值然后再交给末端操作符。
    runBlocking<Unit> {
        (1..5).asFlow()
            .filter {
                println("Filter $it")
                it % 2 == 0
            }
            .map {
                println("Map $it")
                "string $it"
            }.collect {
                println("Collect $it")
            }
    }
    //流的收集可以在当流在一个可取消的挂起函数（例如 delay）中挂起的时候取消
    runBlocking<Unit> {
        withTimeoutOrNull(250) { // 在 250 毫秒后超时
            simple().collect { value -> println(value) }
        }
        println("Done")
    }

    //要取消 Flow 只需要取消collect所在的协程即可
    runBlocking<Unit> {
        val job = GlobalScope.launch {
            val intFlow = flow {
                (1..3).forEach {
                    delay(1000)
                    emit(it)
                }
            }
            intFlow.collect { println(it) }
        }
        delay(2500)
        job.cancelAndJoin()
    }

    //收集发生在主线程中，flow { ... } 则发在另一个后台线程中
    fun simpleFlow(): Flow<Int> = flow {
        for (i in 1..3) {
            Thread.sleep(100) // 假装我们以消耗 CPU 的方式进行计算
            println("Emitting $i")
            emit(i) // 发射下一个值
        }
    }.flowOn(Dispatchers.Default)    // 之上的操作将放到Dispatchers.Default所指定线程中
    runBlocking<Unit> {
        simpleFlow().collect { value ->
            println("Collected $value")
        }
    }

    //显式调用缓冲，减少发射等待
    runBlocking<Unit> {
        val time = measureTimeMillis {
            simple()
                .buffer() // 缓冲发射项，无需等待；不能显示地指定 Dispatchers，将发射操作放到新的线程中
                .collect { value ->
                    delay(300) // 假装我们花费 300 毫秒来处理它
                    println(value)
                }
        }
        println("Collected in $time ms")
    }
    //buffer前后的操作将在两个不同协程中并行。生产消费速度不匹配时会挂起，buffer容量为两个协程之间通信channel的容量
    runBlocking<Unit> {
        flowOf("A", "B", "C")
            .onEach { println("1$it") }
            .buffer()  // <--------------- buffer between onEach and collect
            .collect { println("2$it") }
    }

    //conflate,当收集器处理它们太慢的时候， conflate 操作符可以用于跳过中间值,只处理最新的那个
    //如果缓存池满了，会丢掉将要放入缓存池中的数;不管缓存池的状态如何，会将最后一条数据强行放入缓存池中
    runBlocking<Unit> {
        val time = measureTimeMillis {
            simple()
                .conflate() // 合并发射项，不对每个值进行处理
                .collect { value ->
                    delay(300) // 假装我们花费 300 毫秒来处理它
                    println(value)
                }
        }
        println("Collected in $time ms")
    }

    //xxxLatest,在新值产生的时候取消执行其块中的代码
    runBlocking<Unit> {
        val time = measureTimeMillis {
            simple()
                .collectLatest { value -> // 取消并重新发射最后一个值
                    println("Collecting $value")
                    delay(300) // 假装我们花费 300 毫秒来处理它
                    println("Done $value")
                }
        }
        println("Collected in $time ms")
    }
    flowBuilder()

    flowOperators()

    flowException()

    flowLifecycle()

    flowCancel()
}

fun flowBuilder() {
    println("--------flow()------------")
    runBlocking<Unit> {
        val time = measureTimeMillis {
            flow {
                for (i in 1..5) {
                    delay(100)   // 假装我们在这里做了一些有用的事情
                    emit(i)               // 发送下一个值
                }
            }.collect {
                delay(100)
                println(it)
            }
        }
        println("cost $time")
    }
    println("--------flowOf()------------")
    runBlocking<Unit> {
        flowOf(1, 2, 3, 4, 5)
            .onEach {
                delay(100)
            }
            .collect {
                println(it)
            }
    }
    println("--------asFlow()------------")
    runBlocking<Unit> {
        (1..5).asFlow().collect { value -> println(value) }
    }

    println("--------channelFlow()------------")
    runBlocking {
        val time = measureTimeMillis {
            channelFlow {
                for (i in 1..5) {
                    send(i)
                    delay(100)
                }
                //想要在生成元素时切换调度器，就必须使用 channelFlow 函数来创建 Flow
                withContext(Dispatchers.IO) {
                    send(6)
                }
            }.collect {
                delay(100)
                println(it)
            }
        }
        println("cost $time")
    }
}


fun flowException() {
    println("--------flowException------------")
    fun simple(): Flow<String> = flow {
        for (i in 1..3) {
            println("Emitting $i")
            emit(i) // 发射下一个值
        }
    }
        .map { value ->
            check(value <= 1) { "Crashed on $value" }        //有条件抛异常
            "string $value"
        }
    //可以捕获在发射器或任何过渡或末端操作符中发生的任何异常,
    runBlocking<Unit> {
        try {
            simple()
                .collect { value ->
                    println(value)
                    //check(value.takeLast(1).toInt() <= 2) { "Collected $value" }    //有条件抛异常
                }
        } catch (e: Throwable) {
            println("Caught in try: $e")
        }
    }

    //catch函数可专门用来捕捉来自上游的异常，捕捉到异常后可以 1.重新throw    2.emit    3.忽略或其它处理
    runBlocking {
        flow {
            emit(1)
            throw RuntimeException()
        }
            .catch { println("catch exception：$it") }
//          .catch {  e -> emit("Caught: $e")  }
            .onCompletion { cause ->
                if (cause != null)
                    println("Flow completed exceptionally")
                else
                    println("Done")
            }
            .collect { println(it) }
    }

    //将 collect 操作符的代码块移动到 onEach 中，并将其放到 catch 操作符之前。收集该流必须由调用无参的 collect() 来触发, 这样catch 操作符就可以处理所有异常
    runBlocking {
        (1..5).asFlow()
            .onEach { value ->
                check(value <= 1) { "Collected $value" }
                println(value)
            }
            .catch { e -> println("Caught $e") }
            .collect()
    }

    //retry:如果上游遇到了异常，并使用了 retry 操作符，则 retry 会让 Flow 最多重试 retries 指定的次数。
    runBlocking {
        (1..5).asFlow().onEach {
            if (it == 3) throw RuntimeException("Error on $it")
        }
            .retry(2) {
                if (it is RuntimeException) {
                    return@retry true
                }
                false
            }
//            .retryWhen { cause, attempt ->
//                attempt < 2
//            }
            .onEach { println("Emitting $it") }
            .catch { println("catch exception：$it") }
            .collect()
    }

    // onCompletion 能观察到所有异常并且仅在上游流成功完成（没有取消或失败）的情况下接收一个 null 异常,异常仍然流向下游，处理异常还是交给catch
    runBlocking {
        (1..5).asFlow()
            .onEach { check(it <= 1) { "Collected $it" }
                println( "$it") }
            .onCompletion { cause -> println("Flow completed with $cause") }
            .catch { cause -> println("Caught exception") }
            .collect()
    }
}

fun flowLifecycle() {
    fun simple(): Flow<Int> = (1..6).asFlow()
    runBlocking {
        //try...finally,命令式
        try {
            simple().collect { value -> println(value) }
        } finally {
            println("try...finally Done")
        }

        //onCompletion,声明式
        simple()
            .onCompletion { println("onCompletion Done") }
            .collect { value -> println(value) }

        //onStart、onCompletion
        simple().onEach {
            if (it == 3) throw RuntimeException("Error on $it")
        }
            .onStart { println("Starting flow") }
            .onEach { println("On each $it") }
            .catch { println("Exception : ${it.message}") }
            .onCompletion { println("Flow completed") }
            .collect()
    }
}

fun flowOperators() {
    //Terminal operators:colloect、single/first、toList/toSet/toCollection、count、fold/reduce、launchIn/produceIn/broadcastIn
    //collect，在 onEach 之后使用 collect 末端操作符，那么后面的代码会一直等待直至流被收集
    fun simple(): Flow<Int> = (1..3).asFlow().onEach { delay(100) }
    runBlocking<Unit> {
        println("--------collect-----------")
        simple()
            .onEach { event -> println("Event: $event") }
            .collect() // <--- 等待流收集
        println("Done")
    }
    runBlocking<Unit> {
        println("--------reduce-----------")
        val sum = (1..5).asFlow()
            .map { it * it } // squares of numbers from 1 to 5
            .reduce { a, b -> a + b } // sum them (terminal operator)
        println(sum)
    }
    runBlocking<Unit> {
        println("--------launchIn-----------")
        simple()
            .onEach { event -> println("Event: $event") }
            .launchIn(this)                     //在单独的协程中启动流的收集
        println("Done")
    }

    //Intermediate operators
    suspend fun performRequest(request: Int): String {
        delay(1000) // imitate long-running asynchronous work
        return "response $request"
    }
    //map
    runBlocking<Unit> {
        println("--------map-----------")
        (1..3).asFlow() // a flow of requests
            .map { request -> performRequest(request) }
            .collect { response -> println(response) }
    }
    //transform
    runBlocking<Unit> {
        println("--------transform-----------")
        (1..3).asFlow() // a flow of requests
            .transform { request ->
                emit("Making request $request")
                emit(performRequest(request))
            }
            .collect { response -> println(response) }
    }
    //take
    fun numbers(): Flow<Int> = flow {
        try {
            emit(1)
            emit(2)
            println("This line will not execute")
            emit(3)
        } finally {
            println("Finally in numbers")
        }
    }
    runBlocking<Unit> {
        println("--------take-----------")
        numbers()
            .take(2) // take only the first two
            .collect { value -> println(value) }
    }

    //zip
    runBlocking<Unit> {
        println("--------zip-----------")
        val nums = (1..3).asFlow() // numbers 1..3
        val strs = flowOf("one", "two", "three") // strings
        nums.zip(strs) { a, b -> "$a -> $b" } // compose a single string
            .collect { println(it) } // collect and print
    }

    //combine
    runBlocking<Unit> {
        println("--------combine-----------")
        val nums = (1..3).asFlow().onEach { delay(300) } // numbers 1..3 every 300 ms
        val strs = flowOf("one", "two", "three").onEach { delay(400) } // strings every 400 ms
        val startTime = System.currentTimeMillis() // remember the start time
        nums.combine(strs) { a, b -> "$a -> $b" } // compose a single string with "combine"
            .collect { value -> // collect and print
                println("$value at ${System.currentTimeMillis() - startTime} ms from start")
            }
    }

    //flat
    fun requestFlow(i: Int): Flow<String> = flow {
        emit("$i: First")
        delay(500) // wait 500 ms
        emit("$i: Second")
    }
    runBlocking<Unit> {
        println("--------flat-----------")
        val startTime = System.currentTimeMillis() // remember the start time
        (1..3).asFlow().onEach { delay(100) } // a number every 100 ms
            .flatMapConcat { requestFlow(it) }      //等待内部流完成之前开始收集下一个值
//          .flatMapMerge { requestFlow(it) }       //并发收集所有传入的流，并将它们的值合并到一个单独的流，以便尽快的发射值
//          .flatMapLatest { requestFlow(it) }      //在发出新流后立即取消先前流的收集
            .collect { value -> // collect and print
                println("$value at ${System.currentTimeMillis() - startTime} ms from start")
            }
    }
}

fun flowCancel() {

    println("------------------------flow Cancel-------------------")
    fun foo(): Flow<Int> = flow {
        for (i in 1..5) {
            println("Emitting $i")
            emit(i)
        }
    }
    //for循环flow作cancel检查
    CoroutineScope(Default).launch {
        try {
            foo().collect { value ->
                if (value == 3) cancel()
                println(value)
            }
        }catch (e:Exception){
           println("for...in:${e.message}")
        }

    }
    //大多数flow是不作cancel检查的，需要cancellable()来使其完成cancel检查
    runBlocking<Unit> {
        try {
            (1..5).asFlow().cancellable().collect { value ->
                if (value == 3) cancel()
                println(value)
            }
        } catch (e: Exception) {
            println("cancellable:${e.message}")
        }
    }

}

fun channelExanple() = runBlocking {
    println("--------------------------Channel------------------------")
    //channel Basic
    println("--------channel Basic------------")
    val channel = Channel<Int>()
    launch {//生产数据
        for (x in 1..5) channel.send(x * x)
//        channel.close() //关闭停止
    }
    // 循环接收直到channnel close
    // for (y in channel) println(y)

    val job = launch { repeat(5) { println(channel.receive()) } }
    job.join()
    println("send-receive Done!")

    fun produceSquares() = produce<Int> {
        for (x in 1..8) send(x * x)
    }

    val squares = produceSquares()
    squares.consumeEach { println(it) }
    /*等效替代：
    squares.consume {
       for(ele in this) println(ele)
    }*/
    /*等效替代：
    squares.consume {
        val itor=iterator()
        while(itor.hasNext()) println(itor.next())
    }*/

    println("produce-consume Done!")

    //过produce和actor函数启动的协程结束后都会自动关闭对应的Channel
    val receiveChannel = GlobalScope.produce(capacity = Channel.RENDEZVOUS) {
        for (i in 0..3) {
            println("【${Thread.currentThread().name}】准备发送 $i")
            send(i)		// 等价于channel.send(i)
            println("【${Thread.currentThread().name}】发送完毕 $i")
        }
    }
    val consumer = GlobalScope.launch {
        for (i in receiveChannel) {
            println("【${Thread.currentThread().name}】接收 $i")
        }
    }
    consumer.join()


        val sendChannel = GlobalScope.actor<Int>(capacity = Channel.RENDEZVOUS ) {
            for (i in this) {
                println("【${Thread.currentThread().name}】接收 $i")
            }
        }

        val producer = GlobalScope.launch {
            for (i in 0..3) {
                println("【${Thread.currentThread().name}】准备发送 $i")
                sendChannel.send(i)
                println("【${Thread.currentThread().name}】发送完毕 $i")
            }
        }
        producer.join()


        var cur = numbersFrom(2)
    repeat(10) {
        //从cur中取出第一个元素作为确认的素数
        val prime = cur.receive()
        println(prime)
        //对取走第一个元素后的流中所有元素实施整除过滤
        cur = filter(cur, prime)
    }
    coroutineContext.cancelChildren()
    channelType(2)
    fanInFanOut()
    tickerChannel()
    braodcastChannel()
}

fun fanInFanOut() = runBlocking {
    //扇入：多个协程向一个channel发送数据
    println("--------Fan-in------------")
    val channel = Channel<String>()
    launch { sendString(channel, "foo", 200L) }
    launch { sendString(channel, "BAR!", 500L) }
    repeat(6) {    // receive first six
        println(channel.receive())
    }
    coroutineContext.cancelChildren() // cancel

    //扇出：多个协程从一个channel中接收数据
    println("--------Fan-out------------")
    val producer = produceNumbers()
    repeat(5) { processNumbers(it, producer) }
    delay(950)
    producer.cancel() // canc
}

fun tickerChannel() = runBlocking<Unit> {
    println("--------ticker-----------")
    val tickerChannel = ticker(delayMillis = 100, initialDelayMillis = 0) // create ticker channel
    var nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
    println("Initial element is available immediately: $nextElement")       // no initial delay

    nextElement = withTimeoutOrNull(50) { tickerChannel.receive() } // all subsequent elements have 100ms delay
    println("Next element is not ready in 50 ms: $nextElement")

    nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
    println("Next element is ready in 100 ms: $nextElement")

    // Emulate large consumption delays
    println("Consumer pauses for 150ms")
    delay(150)
    // Next element is available immediately
    nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
    println("Next element is available immediately after large consumer delay: $nextElement")
    // Note that the pause between `receive` calls is taken into account and next element arrives faster
    nextElement = withTimeoutOrNull(60) { tickerChannel.receive() }
    println("Next element is ready in 50ms after consumer pause in 150ms: $nextElement")

    tickerChannel.cancel() // indicate that no more elements are needed
}

@kotlinx.coroutines.ExperimentalCoroutinesApi
fun braodcastChannel() {
    println("--------BroadcastChannel------------")
    runBlocking {
        val broadcastChannel = BroadcastChannel<Int>(5)
        /*替代方法1：
     val channel = Channel<Int>()
     val broadcastChannel = channel.broadcast(5)
     替代方法2：
     val broadcastChannel =   CoroutineScope(Default).broadcast(Default,5){
        for (i in 1..5) {
            send(i)
            println("send $i")
        }
        delay(10000)
        close()
    }*/
        CoroutineScope(Default).launch {
            for (i in 1..5) {
                broadcastChannel.send(i)
                println("send $i")
            }

            delay(10000)
            broadcastChannel.close()
        }
        val receiveChannel1 = broadcastChannel.openSubscription()
        val receiveChannel2 = broadcastChannel.openSubscription()
        val receiveChannel3 = broadcastChannel.openSubscription()
        repeat(3) {
            CoroutineScope(Default).launch {
                var rChannel = when (it) {
                    0 -> receiveChannel1
                    1 -> receiveChannel2
                    2 -> receiveChannel3
                    else -> receiveChannel1
                }
                for (element in rChannel) {
                    println("receiveChannel${it + 1} receive: $element")
                }
            }
        }
    }

    runBlocking {
        val broadcastChannel = GlobalScope.broadcast {
            for (i in 0..3) {
                println("【${Thread.currentThread().name}】准备发送 $i")
                send(i)
                println("【${Thread.currentThread().name}】发送完毕 $i")
            }
        }
        List(3) { index ->
            GlobalScope.launch {
                for (i in broadcastChannel.openSubscription()) {
                    println("【${Thread.currentThread().name}】协程$index 接收 $i")
                }
            }

        }.joinAll()

    }
}
suspend fun sendString(channel: SendChannel<String>, s: String, time: Long) {
    while (true) {
        delay(time)
        channel.send(s)
    }
}

fun CoroutineScope.produceNumbers() = produce<Int> {
    var x = 1 // start from 1
    while (true) {
        send(x++) // produce next
        delay(100) // wait 0.1s
    }
}

fun CoroutineScope.processNumbers(id: Int, channel: ReceiveChannel<Int>) = launch {
    for (msg in channel) {
        println("Processor #$id received $msg")
    }
}

fun printlnx(message: Any?) {
    println("[${Thread.currentThread().name}] $message")
}

fun channelType(kind: Int) = runBlocking {
    println("--------Channel Type------------")


    lateinit var channel: Channel<String>
    when (kind) {
        1 -> channel =
            Channel<String>()           //Rendezvous channel:0尺寸buffer, send和receive要meet on time, 否则挂起. (默认类型),Channel<String>(BUFFERED)
        2 -> channel =
            Channel<String>(1)  //Buffered channel:指定大小, 满了之后send挂起, Channel<String>(BUFFERED),BUFFERED=64
        3 -> channel = Channel<String>(CONFLATED)  //Conflated channel: 新元素会覆盖旧元素, receiver只会得到最新元素, send永不挂起
        4 -> channel = Channel<String>(UNLIMITED)  //Unlimited channel: 无限元素, send不被挂起.
    }
    launch {
        channel.send("A1")
        channel.send("A2")
        println("A done")
    }
    launch {
        channel.send("B1")
        println("B done")
    }
    launch {
        repeat(3) {
            val x = channel.receive()
            println(x)
        }
    }
}

fun CoroutineScope.numbersFrom(start: Int) = produce<Int> {
    var x = start
    while (true) send(x++)    // 开启了一个无限的整数流
}

fun CoroutineScope.filter(numbers: ReceiveChannel<Int>, prime: Int) = produce<Int> {
    for (x in numbers) {
        if (x % prime != 0) send(x)
    }    //numbers流中元素若不能被prime整除，产生一个新的流
}

fun buildCoroutineScope(kind: Int): CoroutineScope {
    val scope = when (kind) {
        1 -> GlobalScope                                   //生命周期和App一致, 无法取消(不存在Job)
        2 -> CoroutineScope(Default)                       //可以取消, 可以通过CoroutineContext控制协程生命周期
        3 -> CoroutineScope(Dispatchers.Unconfined)
        4 -> CoroutineScope(Dispatchers.IO)
        5 -> CoroutineScope(newSingleThreadContext("MyThread"))
        6 -> CoroutineScope(newFixedThreadPoolContext(5, "MyThreadPool"))
        7 -> MyCroutineScope()
        else -> MainScope()   //CoroutineScope(Dispatchers.Main),仅Android有效
    }
    return scope
}

class MyCroutineScope : CoroutineScope {
    private val job = Job()
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Default + job

    fun destory() {
        job.cancel()
    }
}

fun yieldFun() {
    val singleDispatcher = newSingleThreadContext("Single")


    runBlocking {
        val job = GlobalScope.launch {
            launch {
                withContext(singleDispatcher) {
                    repeat(3) {
                        printSomeThingBlock("Task1")
                        yield()
                    }
                }
            }

            launch {
                withContext(singleDispatcher) {
                    repeat(3) {
                        printSomeThingBlock("Task2")
                        yield()
                    }
                }
            }
        }

        job.join()
    }
}

suspend fun printSomeThingBlock(text: String) {
    println(text)
// delay(1000)
    Thread.sleep(1000)
}

fun coroutineException() {
    println("---------------------------coroutineException---------------------")
    runBlocking {
        val job = GlobalScope.launch { // launch 根协程
            println("Throwing exception from launch")
            throw IndexOutOfBoundsException() // 我们将在控制台打印 Thread.defaultUncaughtExceptionHandler
        }
        job.join()
        println("Joined failed job")
        val deferred = GlobalScope.async { // async 根协程
            println("Throwing exception from async")
            throw ArithmeticException() // 没有打印任何东西，依赖用户去调用等待
        }
        try {
            deferred.await()
            println("Unreached")
        } catch (e: ArithmeticException) {
            println("Caught the ArithmeticException")
        }
    }
    runBlocking {
        println("-------------CoroutineExceptionHandler-------------")

        val handler = CoroutineExceptionHandler { _, exception ->
            println("CoroutineExceptionHandler got $exception")
        }
        val job = kotlinx.coroutines.GlobalScope.launch(handler) { // root coroutine, running in GlobalScope
            throw AssertionError()
        }

//通过 async 启动的协程出现未捕获的异常时会忽略 CoroutineExceptionHandler
        val deferred = GlobalScope.async(handler) { // also root, but async instead of launch
            throw ArithmeticException() // 没有打印任何东西，依赖用户去调用 deferred.await()
        }
        try {
        deferred.await()
        } catch (e: ArithmeticException) {
            println("Caught the ArithmeticException")
        }
        joinAll(job)
    }


    runBlocking {
        println("-------------Cancel Exception--------------")
        val job = launch() {
            val handler = CoroutineExceptionHandler { _, exception ->
                println("CoroutineExceptionHandler got $exception")
            }
            val child = launch(handler) {
                try {
                    throw ArithmeticException()
                    delay(Long.MAX_VALUE)

                } catch (e: Exception) {
                    println("Caught:${e.message}")
                } finally {
                    println("Child is cancelled")

                }
            }
            yield()
            println("Cancelling child")
            child.cancel()
            child.join()
            yield()
            println("Parent is not cancelled")
        }
        job.join()
    }

    runBlocking {
        println("-------------supervisorScope Exception--------------")
        val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
            println("${coroutineContext[CoroutineName]} $throwable")
        }
        println(1)
        try {
            //supervisorScope中子协程的异常不会向上传递（不传给父协程和兄弟协程），只向下传递（传给子协程）
            supervisorScope{
            //coroutineScope中子协程异常会触发父协程的取消，进而将整个协程作用域取消
            // coroutineScope { //①
                println(2)
                launch(exceptionHandler + CoroutineName("②")) { // ②
                    println(3)
                    launch(exceptionHandler + CoroutineName("③")) { // ③
                        println(4)
                        delay(100)
                        throw ArithmeticException("Hey!!")
                    }
                    println(5)
                }
                println(6)
                val job = launch { // ④
                    println(7)
                    delay(1000)
                }
                try {
                    println(8)
                    job.join()
                    println("9")
                } catch (e: Exception) {
                    println("10. $e")
                }
            }
            println(11)
        } catch (e: Exception) {
            println("12. $e")
        }
        println(13)
    }
}


fun selectClause() {
    //onReceive
    fun CoroutineScope.fizz() = produce<String> {
        while (true) { // sends "Fizz" every 300 ms
            delay(300)
            send("Fizz")
        }
    }
    fun CoroutineScope.buzz() = produce<String> {
        while (true) { // sends "Buzz!" every 500 ms
            delay(500)
            send("Buzz!")
        }
    }

    runBlocking {
        println("-------------selelct onReceive--------------")
        val fizz = fizz()
        val buzz = buzz()
        repeat(7) {
            select<Unit> { // <Unit> means that this select expression does not produce any result
                fizz.onReceive { value ->  // this is the first select clause
                    println("fizz -> '$value'")
                }
                buzz.onReceive { value ->  // this is the second select clause
                    println("buzz -> '$value'")
                }
            }
        }
        coroutineContext.cancelChildren()
    }

   //onAwait
    suspend fun doOne(): Int {
        delay(500)
        println("【${Thread.currentThread().name}】doOne 计算中")
        return 1
    }

    fun doTwo() = GlobalScope.produce<Int> {
        delay(1000)
        println("【${Thread.currentThread().name}】doTwo 计算中")
        send(2)

    }

    runBlocking {
        println("-------------selelct onAwait--------------")
        val one = async(Dispatchers.Default) { doOne() }
        val two = doTwo()
        select<Unit> {         // Unit表示 select 表达式不返回任何结果
            one.onAwait { value ->
                println("【${Thread.currentThread().name}】one -> $value")
            }
            two.onReceive { value ->
                println("【${Thread.currentThread().name}】two -> $value")
            }
        }
    }
    //onSend
    fun CoroutineScope.produceNumbers(side: SendChannel<Int>) = produce<Int> {
        for (num in 1..10) { // produce 10 numbers from 1 to 10
            delay(100) // every 100 ms
            select<Unit> {
                onSend(num) {} // Send to the primary channel
                side.onSend(num) {} // or to the side channel
            }
        }
    }
    runBlocking {
        println("-------------selelct onSend--------------")
        val side = Channel<Int>() // allocate side channel
        launch { // this is a very fast consumer for the side channel
            side.consumeEach { println("Side channel has $it") }
        }
        produceNumbers(side).consumeEach {
            println("Consuming $it")
            delay(250) // let us digest the consumed number properly, do not hurry
        }
        println("Done consuming")
        coroutineContext.cancelChildren()
    }
}

fun mutableState() {
    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")
    }
    var counter = 0
    runBlocking {
        println("-------------未处理--------------")
        withContext(Default) {
            massiveRun {
                counter++
            }
        }
        println("Counter = $counter")
    }
   //以细粒度限制线程
    counter=0
    val counterContext = newSingleThreadContext("CounterContext")
     runBlocking {
         println("-------------细粒度限制线程--------------")
        withContext(Default) {
            massiveRun {
                // 将每次自增限制在单线程上下文中
                withContext(counterContext) {
                    counter++
                }
            }
        }
        println("Counter = $counter")
    }

    //以粗粒度限制线程
    counter = 0
    runBlocking {
        // 将一切都限制在单线程上下文中
        println("-------------粗粒度限制线程--------------")
        withContext(counterContext) {
            massiveRun {
                counter++
            }
        }
        println("Counter = $counter")
    }
    
    //互斥锁
    val mutex = Mutex()
    counter = 0
    runBlocking {
        println("-------------互斥锁--------------")
        withContext(Default) {
            massiveRun {
                // 用锁保护每次自增
                mutex.withLock {
                    counter++
                }
            }
        }
        println("Counter = $counter")
    }

    //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)
            }
        }
    }
    runBlocking<Unit> {
        println("-------------Actor--------------")
        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
    }

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