【Kotlin】Channel简介

1 前言

        Channel 是一个并发安全的阻塞队列,可以通过 send 函数往队列中塞入数据,通过 receive 函数从队列中取出数据。

        当队列被塞满时,send 函数将被挂起,直到队列有空闲缓存;当队列空闲时,receive 函数将被挂起,直到队列中有新数据存入。

        Channel 中队列缓存空间的大小需要在创建时指定,如果不指定,缓存空间默认是 0。

2 Channel 中 send 和 receive 案例

2.1 capacity 为 0

fun main() {var channel = Channel<Int>()CoroutineScope(Dispatchers.Default).launch { // 生产者repeat(3) {delay(10)println("send: $it")channel.send(it)}}CoroutineScope(Dispatchers.Default).launch { // 消费者repeat(3) {delay(100)var element = channel.receive()println("receive: $element")}}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}

        打印如下。

send: 0
receive: 0
send: 1
receive: 1
send: 2
receive: 2

        说明:send 的 delay 时间比 receive 的 delay 时间短,但是并没有出现连续打印两个 send,而是打印一个 send,再打印一个 recieve,它们交替打印。因为 Channel 中队列的缓存空间默认为 0,在执行了 send 后,如果没有执行 recieve,send 将一直被挂起,直到执行了 receive 才恢复执行 send。

2.2 capacity 大于 0

fun main() {var channel = Channel<Int>(2)CoroutineScope(Dispatchers.Default).launch { // 生产者repeat(3) {delay(10)println("send: $it")channel.send(it)}}CoroutineScope(Dispatchers.Default).launch { // 消费者repeat(3) {delay(100)var element = channel.receive()println("receive: $element")}}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}

        打印如下。

send: 0
send: 1
send: 2
receive: 0
receive: 1
receive: 2

        说明:Channel 中队列的缓存空间为 2,send 的 delay 时间比 receive 的 delay 时间短,因此会出现连续打印多个 send。

3 Channel 中迭代器

3.1 iterator

fun main() {var channel = Channel<Int>()CoroutineScope(Dispatchers.Default).launch { // 生产者repeat(3) {println("send: $it")channel.send(it)}}CoroutineScope(Dispatchers.Default).launch { // 消费者var iterator = channel.iterator()while (iterator.hasNext()) {var element = iterator.next()println("receive: $element")}}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}

        打印如下。

send: 0
send: 1
receive: 0
receive: 1
send: 2
receive: 2

3.2 for in

fun main() {var channel = Channel<Int>()CoroutineScope(Dispatchers.Default).launch { // 生产者repeat(3) {println("send: $it")channel.send(it)}}CoroutineScope(Dispatchers.Default).launch { // 消费者for (element in channel) {println("receive: $element")}}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}

        打印如下。

send: 0
receive: 0
send: 1
send: 2
receive: 1
receive: 2

4 Channel 中 produce 和 actor

        produce 函数用于构造一个生产者协程,并返回一个 ReceiveChannel;actor 函数用于构造一个消费者协程,并返回一个 SendChannel。

4.1 produce

fun main() {var receiveChannel = CoroutineScope(Dispatchers.Default).produce<Int> { // 生产者repeat(3) {println("send: $it")send(it)}}CoroutineScope(Dispatchers.Default).launch { // 消费者for (element in receiveChannel) {println("receive: $element")}}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}

        打印如下。

send: 0
send: 1
receive: 0
receive: 1
send: 2
receive: 2

4.2 actor

fun main() {var sendChannel = CoroutineScope(Dispatchers.Default).actor<Int> { // 生产者repeat(3) {var element = receive()println("receive: $element")}}CoroutineScope(Dispatchers.Default).launch { // 消费者repeat(3) {println("send: $it")sendChannel.send(it)}}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}

        打印如下。

send: 0
send: 1
receive: 0
receive: 1
send: 2
receive: 2

5 Channel 的关闭

        对于一个 Channel,如果我们调用了它的 close 函数,它会立即停止发送新元素,也就是说这时它的 isClosedForSend 会立即返回 true。而由于 Channel 缓冲区的存在,这时候可能还有一些元素没有被处理完,因此要等所有的元素都被读取之后 isClosedForReceive 才会返回 true。

fun main() {var channel = Channel<Int>(3)CoroutineScope(Dispatchers.Default).launch { // 生产者repeat(3) {println("send: $it")channel.send(it)}channel.close()println("producter, isClosedForSend=${channel.isClosedForSend}, isClosedForReceive=${channel.isClosedForReceive}")}CoroutineScope(Dispatchers.Default).launch { // 消费者repeat(3) {var element = channel.receive()println("receive: $element")}println("consumer, isClosedForSend=${channel.isClosedForSend}, isClosedForReceive=${channel.isClosedForReceive}")}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}

        打印如下。

send: 0
send: 1
send: 2
producter, isClosedForSend=true, isClosedForReceive=false
receive: 0
receive: 1
receive: 2
consumer, isClosedForSend=true, isClosedForReceive=true

6 BroadcastChannel

        Channel 的生产者(producter)和消费者(consumer)都可以存在多个,但是同一个元素只会被一个消费者读到。BroadcastChannel 则不然,多个消费者不存在互斥行为。

6.1 Channel 中多个消费者

fun main() {var channel = Channel<Int>(2)CoroutineScope(Dispatchers.Default).launch { // 生产者delay(10)repeat(3) {println("send: $it")channel.send(it)}}repeat(2) { index ->CoroutineScope(Dispatchers.Default).launch { // 消费者for (element in channel) {println("receive-$index: $element")}}}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}

        打印如下。

send: 0
send: 1
send: 2
receive-0: 0
receive-0: 2
receive-1: 1

        说明:结果表明,Channel 中同一个元素只会被一个消费者读到。

6.2 BroadcastChannel 中多个消费者

6.2.1 BroadcastChannel

fun main() {var broadcastChannel = BroadcastChannel<Int>(2)CoroutineScope(Dispatchers.Default).launch { // 生产者delay(10)repeat(3) {println("send: $it")broadcastChannel.send(it)}}repeat(2) { index ->CoroutineScope(Dispatchers.Default).launch { // 消费者var receiveChannel = broadcastChannel.openSubscription()for (element in receiveChannel) {println("receive-$index: $element")}}}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}

        打印如下。

send: 0
send: 1
send: 2
receive-0: 0
receive-0: 1
receive-0: 2
receive-1: 0
receive-1: 1
receive-1: 2

        说明:结果表明,BroadcastChannel 中同一个元素可以被所有消费者读到。

6.2.2 broadcast

fun main() {var channel = Channel<Int>()var broadcastChannel = channel.broadcast(2)CoroutineScope(Dispatchers.Default).launch { // 生产者delay(10)repeat(3) {println("send: $it")broadcastChannel.send(it)}}repeat(2) { index ->CoroutineScope(Dispatchers.Default).launch { // 消费者var receiveChannel = broadcastChannel.openSubscription()for (element in receiveChannel) {println("receive-$index: $element")}}}Thread.sleep(1000) // 阻塞当前线程, 避免程序过早结束, 协程提前取消
}

        打印如下。

send: 0
send: 1
send: 2
receive-1: 0
receive-1: 1
receive-1: 2
receive-0: 0
receive-0: 1
receive-0: 2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/317402.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python可视化学习笔记折线图问题-起始点问题

问题描述&#xff1a; 起始点的位置不对 from pyecharts.charts import Line import pyecharts.options as opts # 示例数据 x_data [1,2,3,4,5] y_data [1, 2, 3, 4, 5] # 创建 Line 图表 line Line() line.add_xaxis(x_data) line.add_yaxis("test", y_data) li…

基于Hyperf的CMS,企业官网通用php-swoole后台管理系统

2023年9月11日10:47:00 仓库地址&#xff1a; https://gitee.com/open-php/zx-hyperf-cms CMS&#xff0c;企业官网通用PHP后台管理系统 框架介绍 hyperf SCUI 后端开发组件 php 8.1 hyperf 3.1 数据库 sql(使用最新日期文件) hyperf\doc\sql_bak mysql 8. 系统默认账号…

STM32 F103C8T6学习笔记17:类IIC通信—MLX90614红外非接触温度计

今日学习配置MLX90614红外非接触温度计 与 STM32 F103C8T6 单片机的通信 文章提供测试代码讲解、完整工程下载、测试效果图 本文需要用到的大概基础知识&#xff1a;1.3寸OLED配置通信显示、IIC通信、 定时器配置使用 这里就只贴出我的 OLED驱动方面的网址链接了&#xff1a…

ChatGPT4.0知识问答、DALL-E生成AI图片、Code Copilot辅助编程,打开新世界的大门

目录 1、DALL-E 文字转图片 在线AI修改2、Write For Me3、Code Copilot 目前最强的AI编程大模型4、Diagrams: Show Me5、Instant Website [Multipage] 网站合成神器6、AskYourPDF Research Assistant 无限PDF7、Diagrams & Data: Research, Analyze, Visualize 精读Excel …

TCP/IP和HTTP协议

TCP/IP OSI 七层模型在提出时的出发点是基于标准化的考虑&#xff0c;而没有考虑到具体的市场需求&#xff0c;使得该模型结构复杂&#xff0c;部分功能冗余&#xff0c;因而完全实现 OSI 参考模型的系统不多。而 TCP/IP 参考模型直接面向市场需求&#xff0c;实现起来也比较…

LeetCode 543.二叉树的直径

题目描述 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 示例 1&#xff1a; 输入&#xff1a;root [1,2,3,4,5]…

报错“Install Js dependencies failed”【鸿蒙开发Bug已解决】

文章目录 项目场景:问题描述原因分析:解决方案:此Bug解决方案总结Bug解决方案寄语项目场景: 最近也是遇到了这个问题,看到网上也有人在询问这个问题,本文总结了自己和其他人的解决经验,解决了【报错“Install Js dependencies failed”】的问题。 报错如下 问题描述 …

【高质量】2024五一数学建模C题保奖思路+代码(后续会更新)

你的点赞收藏是我后续更新的最大动力&#xff01; 一定要点击文末的卡片&#xff0c;那是获取资料的入口&#xff01; 你是否在寻找数学建模比赛的突破点&#xff1f; 作为经验丰富的数学建模团队&#xff0c;我们将为你带来2024 年五一数学建模&#xff08;C题&#xff09;…

复旦微JFM7VX690计算后IO接口模块,用于雷达信号处理、数据处理等需要高速密集计算的应用场景

计算后IO接口模块 1 介绍 1.1 产品概述 计算后IO接口模块主要由复旦微JFM7VX690型FPGA、国产以太网收发器YT8521、国产BMC芯片GD32F450、国产CPLD芯片EF2L45BG256B、国产内存颗粒等主要芯片组成&#xff0c;采用标准6U VPX尺寸设计。 本计算后IO接口模块主要用于雷达信号处…

Nginx负载均衡主备模式

1. 背景 使用Nginx代理后端服务&#xff0c;有时候某些服务是不能使用多台负载均衡&#xff0c;但又想保障高可用&#xff0c;所以采用主备模式&#xff0c;记录如下&#xff1a; 2. 参考 nginx 负载均衡Nginx-负载均衡-后端状态max_conns、down、backup、max_fails、fail_t…

【webrtc】MessageHandler 1: 基于线程的消息处理:以10毫秒处理音频为例

基于m98 G:\CDN\rtcCli\m98\src\audio\null_audio_poller.h分发的消息由MessageHandler 类通过其抽象接口OnMessage 实现处理 NullAudioPoller NullAudioPoller 是一个处理audio的消息的分发器 poll 启动:

2024深圳杯数学建模竞赛A题(东三省数学建模竞赛A题):建立火箭残骸音爆多源定位模型

更新完整代码和成品完整论文 《2024深圳杯&东三省数学建模思路代码成品论文》↓↓↓&#xff08;浏览器打开&#xff09; https://www.yuque.com/u42168770/qv6z0d/zx70edxvbv7rheu7?singleDoc# 2024深圳杯数学建模竞赛A题&#xff08;东三省数学建模竞赛A题&#xff0…

【Go 语言入门专栏】Go 语言的起源与发展

前言 Go 语言是当下最为流行的编程语言之一&#xff0c;大约在 2020、2021 年左右开始于国内盛行&#xff0c;许多大厂很早就将部分 Java 项目迁移到了 Go&#xff0c;足可看出其在性能方面的优越性。 相信各位都知道&#xff0c;在爬虫业务中&#xff0c;并发是一个关键的需…

解决iview(view ui)中tabs组件中使用图片预览组件ImagePreview,图片不显示问题

同学们可以私信我加入学习群&#xff01; 正文开始 前言一、问题描述二、原因分析三、解决方案总结 前言 最近在写个人项目的web端和浏览器插件&#xff0c;其中一个功能是base64和图片的转换。因为分成四个小功能&#xff0c;所以使用的iview的tabs来展示不同功能&#xff0c…

如何解决DA14531编译工程出现大量报错的问题

在编译DA14531某个工程时&#xff0c;在这台电脑可以编译&#xff0c;另外一台电脑就编译不过&#xff0c;出现很多错误问题。那要怎样处理呢&#xff1f; 建议安装新MDK版本 可能是MDK版本问题&#xff0c;在不同的电脑安装不同的MDK版本&#xff0c;用新的版本可以编译通过&…

计算机网络—数据链路层

一、数据链路层的基本概念 结点&#xff1a;主机、路由器 链路&#xff1a;网络中两个结点之间的物理通道&#xff0c;链路的传输介质主要有双绞线、光纤和微波。分为有线链路、无线链路 数据链路&#xff1a;网络中两个结点之间的逻辑通道&#xff0c;把实现控制数据协议的…

java在应用程序里获取不到扬声器设备,如何解决?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

MF(推荐系统的矩阵分解技术)论文笔记

论文概述 推荐系统的矩阵分解技术可以为用户提供更为准确的个性化推荐&#xff0c;对比传统的近邻技术&#xff0c;矩阵分解技术可以纳入更多信息&#xff0c;如隐式反馈、时间效应和置信度 近邻技术&#xff1a;基于用户或物品之间的相似性进行推荐&#xff0c;当用户之间已…

针孔相机模型原理坐标系辨析内参标定流程内参变换

针孔相机的内参标定 针孔相机原理真空相机模型图片的伸缩和裁剪变换 内参标定———非线性优化张正定标定详细原理(含公式推导)通过多张棋盘格照片完成相机的内参标定流程(C代码)其他工具箱 相机分为短焦镜头和长焦镜头&#xff0c;短焦镜头看到的视野更广阔&#xff0c;同样距…

CSS高级选择器

一、属性选择器 以value开头的att属性的E元素&#xff1a;E[att^"value"]{ ;} a[href^http]{background-color"red";} css a[href^http]{background-color"red"; } html <!DOCTYPE html> <html lang"en"> <head&…