Kotlin Channel 热流

协程:Channel 热流

1、Channel是什么?

  1. 生产者:多个协程
  2. 消费者:多个协程
  3. 中间:Channel 管道 并发安全队列
  4. 发送send
  5. 接收recv

协程间通信

1、Channel可以用于协程间通信

kotlin 复制代码
    // 通道Channel
    val channel = Channel<Int>()

    // 生产者
    launch{
        (1..6).forEach {
            delay(1000L)
            println("我生产了一个:$it")
            channel.send(it)
        }
    }

    // 消费者
    launch{
        (1..6).forEach {
            val r=  channel.receive()
            println("消费了一个:$r")
        }
    }

capacity

1、生产速度>消费速度

  1. 如果缓冲区满了,send会挂起,消费完后再生产
  2. capacity,默认容量,0

UNLIMITED:send不再挂起

  1. 容量接近于无限
  2. 容量不满就不会挂起
kotlin 复制代码
    // 通道Channel
    val channel = Channel<Int>(Channel.UNLIMITED)

消费方式

kotlin 复制代码
        // 第一种发方式 消费
        (1..8).forEach {
            delay(2000L)
            val r=  channel.receive()
            println("消费了一个:$r")
        }

iterator

kotlin 复制代码
        // 第二种发方式 消费
        val it = channel.iterator()
        while (it.hasNext()) {
            val item = it.next()
            delay(2000L)
            println("消费了一个:$item")
        }

item in channel

kotlin 复制代码
        // 第三种发方式 消费
        for (item in channel) {
            delay(2000L)
            println("消费了一个:$item")
        }

快捷方式

produce和ReceiveChannel

  1. produce快速构建消费者
kotlin 复制代码
// 生产者的快捷方式
    val produce = produce {
        (1..20).forEach { delay(2000L) ; send(it) }
    }

    // 普通的消费
    launch {
        for (item in produce) {
            println("消费了一个:$item")
        }
    }

    // receive()接收数据,有数据没有消费,send会一直阻塞
    launch {
        println("消费了一个:${produce.receive()}")
        delay(2000)
        println("消费了一个:${produce.receive()}")
        println("消费了一个:${produce.receive()}")
        println("消费了一个:${produce.receive()}")
        println("消费了一个:${produce.receive()}")
        println("消费了一个:${produce.receive()}")
    }

produce(capacity = 100),会增加缓冲区,只要没有放满send不会再阻塞。

actor和SendChannel

  1. actor快速构建消费者
kotlin 复制代码
    // 消费者的快捷方式
    val consumer = actor<Int> {
        (1..20).forEach {
            println("消费了一个:${receive()}")
        }
    }

    // 普通的生成
    launch {
        (1..20).forEach { delay(2000L) ; consumer.send(it) }
    }

close

1、channel.close

  1. 关闭
  2. 一般是生产者去close

isClosedForSend

channel.close() 之前 isClosedForSend == false

channel.close() 之后 isClosedForSend == true

kotlin 复制代码
    // 生产者
    launch {
        (1..6).forEach {
            if (!channel.isClosedForSend) {
                channel.send(it)
                println("我生产了一个$it")

                // if (it == 3) channel.close() // 大部分情况下,是生产者 去close
            }
        }
        println("close前 isClosedForSend:${channel.isClosedForSend} " +
                " isClosedForReceive:${channel.isClosedForReceive}")
        channel.close()
        println("close后 isClosedForSend:${channel.isClosedForSend} " +
                " isClosedForReceive:${channel.isClosedForReceive}")
    }

isClosedForReceive

如果消费完了 isClosedForReceive == true, 否则就是false

如果缓冲区里面还有内容,没有消费完 也是 false

kotlin 复制代码
    // 消费者
    launch {
        try {
            for (i in channel) {
                delay(2000L)
                println("我消费了一个:$i")
            }
        }finally {
            println("finally isClosedForSend:${channel.isClosedForSend} " +
                    " isClosedForReceive:${channel.isClosedForReceive}")
        }
    }

BroadcastChannel

1、广播给所有消费者,多个地方可以接收到

  1. 创建
kotlin 复制代码
    val channel = Channel<Int>()
    val broadcastChannel = channel.broadcast(Channel.BUFFERED)
  1. 生产
kotlin 复制代码
    // 生产者
    launch {
        repeat(8) {
            delay(1000L)
            broadcastChannel.send(it + 100001) // 发送
        }
        broadcastChannel.close() // 关闭
    }

openSubscription

  1. 消费
kotlin 复制代码
    repeat(8) {
        // 消费者
        launch {
            val r = broadcastChannel.openSubscription()
            for (i in r) {
                println("协程$it ---- 消费者 ${i}")
            }
        }
    }

select

1、select: 择优选择数据,谁先返回用谁的

  1. 加载首页数据,可以作缓存
  2. 缓存有用缓存,缓存不存在去请求
  3. "慢的不会再执行"会被cancel

2、select 是一个用于多路选择的结构,可以同时等待多个挂起函数或通道的操作完成。它类似于 switch 或 if-else 的多路分支语句,但是它是用于协程的异步操作。

kotlin 复制代码
suspend fun selectExample() {
    select<Unit> {
        someChannel.onReceive { value ->
            // 处理从通道接收到的值
        }
        someDeferred.onAwait { result ->
            // 处理异步操作完成后的返回值
        }
        onTimeout(1000) {
            // 在指定时间内没有任何操作完成时执行
        }
    }
}

3、select可以用于上游,也可以用于下游

onAwait

  1. async有onAwait
kotlin 复制代码
data class Home(val info1: String, val info2: String)

data class HomeRequestResponseResultData(val code: Int, val msg: String, val home: Home)

// 请求本地加载首页数据
fun CoroutineScope.getHomeLocalData() = async (Dispatchers.IO) {
    delay(3000)
    Home("数据1...", "数据1...")
}

// 请求网络服务器加载首页数据
fun CoroutineScope.getHomeRemoteData() = async (Dispatchers.IO) {
    delay(6000)
    Home("数据3...", "数据4...")
}
kotlin 复制代码
    launch {
        val localRequestAction = getHomeLocalData()
        val remoteRequestAction = getHomeRemoteData()

        val resultResponse = select<HomeRequestResponseResultData> {
            localRequestAction.onAwait {
                // 做校验 工作
                // ...
                // 省略1000行代码
                HomeRequestResponseResultData(200, "恭喜你,请求成功", it) // 最后一行作为返回值
            }

            remoteRequestAction.onAwait {
                // 做校验 工作
                // ...
                // 省略1000行代码
                HomeRequestResponseResultData(200, "恭喜你,请求成功", it) // 最后一行作为返回值
            }
        }
        println("resultResponse:$resultResponse")
    }

2、async需要在调用的CoroutineScope中执行

kotlin 复制代码
fun CoroutineScope.getHomeLocalData() = async (Dispatchers.IO) {
    delay(3000)
    Home("数据1...", "数据1...")
}
// 对CoroutineScope扩展

channel数组

  1. 哪个更快选择哪个Channel
onReceive
  1. onReceive: 接收数据后的回调
kotlin 复制代码
    val channels = arrayOf(Channel<String?>(), Channel<String?>())

    launch {
        delay(6000)
        channels[0].send("login successful")
    }

    launch {
        delay(8000)
        channels[1].send("register successful")
    }

    val receiveResult = select<String ?> {
        for (channel in channels) {
            channel.onReceive {
                // 做校验 工作
                // ...
                // 省略1000行代码
                "[$it]" // 最后一行作为返回值
            }
        }
    }
    println(receiveResult)

onJoin

launch无返回值,但想看谁执行的最快

kotlin 复制代码
    val job1 = launch {println("launch1 run")} // 无返回值
    val job2 = launch {println("launch2 run")} // 无返回值
    select<Unit> {
        job1.onJoin { println("launch1 执行完成了 很快") }
        job2.onJoin { println("launch2 执行完成了 很快") }
    }

onSend

发送数据,并且显示回调的内容(上游)

kotlin 复制代码
    // 准备Channel数组
    val channels = arrayOf(Channel<Char>(), Channel<Char>())

    // 协程一:Channel 的 发射源
    launch(Dispatchers.Default) {
        select<Unit> {
            // 并行干活,send
            launch {
                channels[0].onSend('女') {
                    println("channels[0].onSend('女') { $it }")
                }
            }
            // 并行干活,send
            launch {
                channels[1].onSend('男') {
                    println("channels[1].onSend('男') { $it }")
                }
            }
        }
    }
    // 协程二:下游 接收阶段
    launch { println("channel1 下游接收 ${channels[0].receive()}") }
    launch { println("channel2 下游接收 ${channels[1].receive()}") }

输出:
channel1 下游接收 女
channels[0].onSend('女') { RendezvousChannel@34206005{EmptyQueue} }
// 1. onSend先发送消息
// 2. 下游接收到
// 3. onSend回调打印消息

await

复用Channel

相关推荐
猷咪23 分钟前
C++基础
开发语言·c++
IT·小灰灰25 分钟前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧27 分钟前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q27 分钟前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳027 分钟前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾27 分钟前
php 对接deepseek
android·开发语言·php
2601_9498683631 分钟前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
星火开发设计1 小时前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识
qq_177767371 小时前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos
一匹电信狗1 小时前
【LeetCode_21】合并两个有序链表
c语言·开发语言·数据结构·c++·算法·leetcode·stl