当前位置: 首页 > article >正文

协程学习笔记2

一、Flow通过flow异步返回多个值fun simpleFlow() flowInt { for (i in 1..5) { delay(1000) emit(i) } } Test fun 通过flow异步返回多个值() runBlocking { launch { for (k in 1..5) { delay(500) println(k:$k) } } delay(500) simpleFlow().collect { println(it) } println(end) delay(5000) }执行结果k:1 k:2 1 k:3 k:4 2 k:5 3 4 5 end冷流Flow是一种类似于序列的冷流flow构建器中的代码直到遇到末端操作符(例如被收集)的时候才会运行。Test fun 冷流在收集时才会开始执行()runBlocking { val flowsimpleFlow() println(创建冷流) delay(1000) println(冷流未执行) flow.collect { println(it) } println(冷流执行结束) }执行结果创建冷流 冷流未执行 1 2 3 4 5 冷流执行结束流构建器flowOf构建器定义了一个发射固定值集的流。Test fun 流构建器()runBlocking { flowOf(1,2,3) .onEach { delay(1000) } .collect { println(it) } }流上下文流的收集总是在调用协程的上下文中发生Flow 发射、操作符执行、收集时能正确继承 / 保留你指定的协程上下文。流的该属性称为上下文保存。fun contextFlow()flow{ println(Thread.currentThread().name) for (i in 1..5) { delay(1000) emit(i) } } Test fun 流的上下文保存()runBlocking { contextFlow().collect { println($it : ${Thread.currentThread().name}) } }执行结果flow运行的线程与协程的相同。Test worker coroutine#1 1 : Test worker coroutine#1 2 : Test worker coroutine#1 3 : Test worker coroutine#1 4 : Test worker coroutine#1 5 : Test worker coroutine#1flow{...}构建器中的代码必须遵循上下文保存属性并且不允许从其他上下文中发射(emit)。例如不可以使用withContext来切换上下文。flow { withContext(Dispatchers.IO) { // 报错 emit(1) } }flowOn操作符该函数用于更改流发射的上下文。fun contextFlow()flow{ println(Thread.currentThread().name) for (i in 1..5) { //模拟IO操作 delay(1000) emit(i) } }.flowOn(Dispatchers.IO) //上下文切换 Test fun 流的上下文保存()runBlocking { contextFlow().collect { println($it : ${Thread.currentThread().name}) } }执行结果flow运行的线程与协程的不同。DefaultDispatcher-worker-1 coroutine#2 1 : Test worker coroutine#1 2 : Test worker coroutine#1 3 : Test worker coroutine#1 4 : Test worker coroutine#1 5 : Test worker coroutine#1flowOn只作用于他上面的代码下面的代码还是运行在上下文中的线程。Test fun flowOn只作用其上面的代码()runBlocking { flowOf(1,2,3) .onEach { delay(500) println(flow上面$it ${Thread.currentThread().name}) } .flowOn(Dispatchers.IO) .onEach { delay(500) println(flow下面$it ${Thread.currentThread().name}) } .collect { println(收集元素$it ${Thread.currentThread().name}) } }执行结果flow上面的代码运行在IO线程flow下面的代码运行在协程中。若想要更直观的结果可以将第二个onEach中的delay(500)删掉这样可以使接收速度大于发送速度这样子的话结果将会是flow上面、flow下面、收集元素这样的顺序出现。flow上面1 DefaultDispatcher-worker-1 coroutine#2 flow上面2 DefaultDispatcher-worker-1 coroutine#2 flow下面1 Test worker coroutine#1 收集元素1 Test worker coroutine#1 flow上面3 DefaultDispatcher-worker-1 coroutine#2 flow下面2 Test worker coroutine#1 收集元素2 Test worker coroutine#1 flow下面3 Test worker coroutine#1 收集元素3 Test worker coroutine#1在指定协程中收集流fun event()(1..3) .asFlow() .onEach { delay(1000) } .flowOn(Dispatchers.Default) Test fun 在指定协程中收集流()runBlocking { val scope CoroutineScope(Dispatchers.IO) val jobevent().onEach { println(Event:$it ${Thread.currentThread().name}) } .launchIn(scope) job.join() }执行结果虽然不是在同一个线程中运行的但还是同一个协程。Event:1 DefaultDispatcher-worker-3 coroutine#2 Event:2 DefaultDispatcher-worker-1 coroutine#2 Event:3 DefaultDispatcher-worker-3 coroutine#2launchIn相当于一个末端操作符相当于在对应协程中用launch启动一个子协程子协程中有流的收集(没有末端操作符流不会执行)下面是它的源码。public fun T FlowT.launchIn(scope: CoroutineScope): Job scope.launch { collect() // tail-call }流的超时取消fun 流的超时取消--产生流() flowInt{ for (i in 1..3){ emit(i) println(发送数据$i) } } Test fun 流的超时取消()runBlocking { withTimeoutOrNull(2500){ 流的超时取消--产生流().collect { delay(1000) println(收集数据$it) } } println(等待超时) }执行结果emit()是挂起函数如果buffer为0(或者未设置buffer,下面处理背压中有示例展示设置buffer的情况)它会等待collect中的代码执行完成之后再恢复。所以会出现收集数据先于发送数据。收集数据1 发送数据1 收集数据2 发送数据2 等待超时流的取消检测Test fun 流没有正常取消()runBlocking { (1..5).asFlow().collect { println(it) if(it3) cancel() } }执行结果出现取消异常但是取消异常是在5之后说明没有正常地取消流。1 2 3 4 5添加cancellable()Test fun 流没有正常取消()runBlocking { (1..5).asFlow().cancellable().collect { println(it) if(it3) cancel() } }执行到3之后就会出现取消异常说明正确地取消流。1 2 3用emit发射数据时emit函数会自动检测流是否被取消。使用缓冲与flowOn处理背压当生产者生产速度大于消费者消费速度时会产生背压。设置buffer解决背压fun 背压-发射数据()flowInt{ for(i in 1..3){ delay(500) emit(i) println(发射$i) } } Test fun 设置buffer解决背压()runBlocking { 背压-发射数据() .buffer(3) .collect { delay(1000) println(接收$it) } }执行结果发射1 发射2 接收1 发射3 接收2 接收3用flowOn解决背压Test fun 使用folwOn解决背压()runBlocking { 背压-发射数据() .flowOn(Dispatchers.Default) .collect { delay(1000) println(接收$it) } }执行结果发射1 发射2 接收1 发射3 接收2 接收3流的超时取消这一小节中有提到buffer。当flow上下文与协程上下文相同时buffer默认为0只有当数据收集之后才可以发射下一个数据当用flowOn切换上下文时会自动创建一个不为0的buffer从而解决背压问题。flow除了设置buffer还有其他的一些设置。conflate(),可收集最新的数据中间发射的数据不收集collectLatest(),只收集最后一个值。操作符转换操作符transformTest fun transform转换操作符()runBlocking { (1..3).asFlow() .transform { emit(it) emit(it5) }.collect { println(it) } }1 6 2 7 3 8map会自动返回最后的lambda表达式transform要自己手动emit。限长操作符takefun take-发射数据()flow { try { emit(1) emit(2) println(不会发射) emit(3) }finally { println(未全部发射) } } Test fun take限长操作符()runBlocking { take-发射数据().take(2).collect { println(it) } }1 2 未全部发射末端操作符末端操作符是在流上用于启动流收集的函数。collect、toList、toSet、first、single、reduce、fold。组合操作符zipTest fun zip组合操作符()runBlocking { val nums(1..3).asFlow().onEach { delay(300) } val strflowOf(one,two,three).onEach { delay(400) } val startTime System.currentTimeMillis() nums.zip(str){ nums,str - $nums $str }.collect { println(${System.currentTimeMillis()-startTime} : $it) } }435 : 1 one 835 : 2 two 1244 : 3 three展平操作符展平操作符就是专门处理流里套流FlowFlowT → 展开成普通流FlowTTest fun 展平操作符()runBlocking { val startTime System.currentTimeMillis() (1..3).asFlow() .onEach { delay(100) } .flatMapConcat { //其它展开操作符修改这一行就行 flow { emit(it) delay(1000) emit((it10)) } } .collect { println(${System.currentTimeMillis()-startTime} : 收集 ${it}) } }flatMapConcat126 : 收集 1 1147 : 收集 11 1255 : 收集 2 2273 : 收集 12 2375 : 收集 3 3396 : 收集 13flatMapMerge152 : 收集 1 251 : 收集 2 361 : 收集 3 1158 : 收集 11 1267 : 收集 12 1363 : 收集 13flatMapLatest140 : 收集 1 289 : 收集 2 396 : 收集 3 1407 : 收集 13流的异常捕获try/catch块Test fun try catch块捕获异常()runBlocking{ try { simpleFlow2().collect { println(it) check(it2) } }catch (e: Exception){ e.printStackTrace() } }catch函数Test fun catch函数捕获异常()runBlocking { flow{ emit(1) delay(200) emit(2) throw IOException() delay(200) emit(3) }.catch { println(it) }.collect { println(it) } }1 2流的完成当流收集完成时普通情况或异常情况它可以需要执行一个动作。命令式finally块

相关文章:

协程学习笔记2

一、Flow通过flow异步返回多个值fun simpleFlow() flow<Int> {for (i in 1..5) {delay(1000)emit(i)} }Test fun 通过flow异步返回多个值() runBlocking {launch {for (k in 1..5) {delay(500)println("k:$k")}}delay(500)simpleFlow().collect {println(it)…...

嵌入式工程师必学(176):深入ADC

前言: 对于要理解芯片而言,不仅要理解芯片内部的模块构成,接口就是要知道接口内部结构是怎么构成的,但是每个接口功能而言,内部和外部是一个有联系有关联的系统,要一起看,电压的分配,电流的流动,电阻的匹配 ,电容的充放电。 ADC这个接口看似简单,也不简单。ADC芯片…...

和我一起学软件架构:C编译流程

引言 我们基于两个材料进行实验&#xff1a;&#xff08;一个简单的C语言代码) (GNU工具-GCC) 源代码 // hello.c #include <stdio.h> #define PI 3.14159 int main() {double radius 5.0;double area PI * radius * radius;printf("Area %f\n", area);re…...

【力扣-239. 滑动窗口最大值[特殊字符]】Python笔记

单调队列与滑动窗口算法详解滑动窗口概念滑动窗口技术用于在数组或字符串上维护一个固定大小的子区间。传统暴力解法每次滑动窗口后重新计算极值会导致O(nk)时间复杂度&#xff0c;在数据规模较大时效率低下。单调队列特性单调队列通过特殊结构保证队列元素始终有序&#xff1a…...

linux的指令(2)

find&#xff08;用于查找文件&#xff09;find目录/ -name文件名&#xff08;文件名中加*是通配符&#xff0c;如第二张图&#xff09;which 用于查找指令通常指令都是处于bin文件中&#xff08;所有指令本质上都已Linux中的一个文件&#xff09;&#xff08;is where用于少数…...

工具管理化技术工具选型与集成评估

工具管理化技术工具选型与集成评估&#xff1a;提升企业效率的关键路径 在数字化转型的浪潮中&#xff0c;技术工具的选型与集成已成为企业提升运营效率、优化资源分配的核心环节。面对市场上种类繁多的技术工具&#xff0c;如何科学评估、合理选型&#xff0c;并实现高效集成…...

Phi-3 Forest Laboratory 工具链整合:Visual Studio Code高效开发插件推荐与配置

Phi-3 Forest Laboratory 工具链整合&#xff1a;Visual Studio Code高效开发插件推荐与配置 你是不是也遇到过这种情况&#xff1a;写代码写到一半&#xff0c;突然卡在一个函数实现上&#xff0c;或者面对一段复杂的遗留代码&#xff0c;需要花半天时间去理解它的逻辑。传统…...

AnythingtoRealCharacters2511部署教程:NVIDIA Jetson Orin Nano边缘端轻量部署方案

AnythingtoRealCharacters2511部署教程&#xff1a;NVIDIA Jetson Orin Nano边缘端轻量部署方案 1. 引言&#xff1a;让动漫角色走进现实 你是否曾经想过&#xff0c;让喜欢的动漫角色变成真实人物的样子&#xff1f;现在&#xff0c;通过AnythingtoRealCharacters2511模型&a…...

Nano-Banana部署优化指南:Euler Ancestral调度器提升生成稳定性

Nano-Banana部署优化指南&#xff1a;Euler Ancestral调度器提升生成稳定性 1. 项目概述与价值 Nano-Banana Studio是一款专注于物理结构拆解风格的AI创作工具&#xff0c;能够将复杂的服装、鞋包或电子产品转化为极具美感的平铺图&#xff08;Knolling&#xff09;或分解视图…...

YOLO12与UltraISO结合:制作启动U盘中的图像识别

YOLO12与UltraISO结合&#xff1a;制作启动U盘中的图像识别 1. 引言 每次制作系统启动U盘时&#xff0c;最让人头疼的就是确认下载的ISO镜像文件是否正确无误。下载过程中网络波动、文件损坏&#xff0c;或者不小心选错了版本&#xff0c;都可能导致制作出来的启动盘无法正常…...

游戏战斗系统伤害计算与技能冷却

在充满策略与挑战的游戏世界中&#xff0c;战斗系统的伤害计算与技能冷却机制是决定胜负的核心要素。无论是角色扮演游戏中的BOSS战&#xff0c;还是MOBA竞技中的团战对决&#xff0c;精准的伤害预估与技能节奏把控往往能扭转战局。本文将深入剖析战斗系统的设计逻辑&#xff0…...

AnimateDiff模型架构解析:从文生图到文生视频的技术演进

AnimateDiff模型架构解析&#xff1a;从文生图到文生视频的技术演进 深入理解AnimateDiff如何通过精巧的架构设计&#xff0c;将静态图像生成进化为动态视频创作 1. 引言&#xff1a;视频生成的技术挑战 视频生成相比图像生成面临着一个核心挑战&#xff1a;时间维度的一致性。…...

一键部署人脸识别:Retinaface+CurricularFace镜像快速体验

一键部署人脸识别&#xff1a;RetinafaceCurricularFace镜像快速体验 1. 为什么选择这个镜像 你是否遇到过这样的情况&#xff1a;想尝试人脸识别技术&#xff0c;却被复杂的模型部署和环境配置搞得焦头烂额&#xff1f;这个RetinafaceCurricularFace镜像就是为了解决这个问题…...

节省50%编码时间:Qwen2.5-Coder-1.5B在真实项目中的应用分享

节省50%编码时间&#xff1a;Qwen2.5-Coder-1.5B在真实项目中的应用分享 1. 为什么选择Qwen2.5-Coder-1.5B 1.1 从手动编码到AI辅助的转变 在过去的三个月里&#xff0c;我们的开发团队从一个完全手动编码的工作流程&#xff0c;逐步过渡到使用Qwen2.5-Coder-1.5B作为日常开…...

Java 从入门到精通(六):抽象类与接口到底怎么选?

Java 从入门到精通&#xff08;六&#xff09;&#xff1a;抽象类与接口到底怎么选&#xff1f; 学到继承和多态之后&#xff0c;很多人会马上遇到一个新问题&#xff1a; 抽象类和接口看起来都像是在“定义规范”&#xff0c;那它们到底有什么区别&#xff1f; 更麻烦的是&…...

手把手教你用OMNet++和NESTING搭建TSN仿真环境(Ubuntu 16.04/18.04版)

在Ubuntu系统中构建TSN仿真环境的完整指南&#xff1a;OMNet与NESTING实战 时间敏感网络&#xff08;TSN&#xff09;作为工业自动化、车载通信等关键领域的核心技术&#xff0c;其仿真验证环节的重要性不言而喻。本文将带您完成从零开始在Ubuntu 16.04/18.04系统上搭建基于OMN…...

NetBox IPAM实战:如何用Redis提升你的网络管理效率(附详细配置步骤)

NetBox IPAM实战&#xff1a;Redis加速网络管理的全流程指南 在数字化基础设施快速扩张的今天&#xff0c;网络地址管理(IPAM)系统正面临前所未有的性能挑战。NetBox作为开源IPAM领域的标杆工具&#xff0c;其默认配置虽然能满足基础需求&#xff0c;但当遇到大规模网络设备管理…...

Python 异步下载任务调度机制

Python异步下载任务调度机制&#xff1a;高效处理网络IO的利器 在当今数据驱动的时代&#xff0c;高效下载网络资源成为许多应用的核心需求。Python凭借其强大的异步编程能力&#xff0c;通过asyncio、aiohttp等库构建的异步下载任务调度机制&#xff0c;能够显著提升网络IO密…...

墨语灵犀快速上手:Anaconda虚拟环境配置与模型调用测试

墨语灵犀快速上手&#xff1a;Anaconda虚拟环境配置与模型调用测试 你是不是刚接触大模型开发&#xff0c;想快速搭建一个干净、独立的Python环境来测试模型&#xff1f;或者你已经在多个项目间切换&#xff0c;被各种依赖冲突搞得焦头烂额&#xff1f; 今天&#xff0c;我就…...

使用WebSocket构建实时应用

WebSocket技术为实时应用开发带来了革命性变化。传统HTTP协议只能实现单向通信&#xff0c;而WebSocket支持全双工通信&#xff0c;使得服务器可以主动推送数据到客户端&#xff0c;极大提升了实时交互体验。如今&#xff0c;从在线聊天到股票行情&#xff0c;从多人游戏到协同…...

3个月速通大模型:告别 GitHub 沉迷,从算法老炮到 LLM 工程师!

如果你在读这篇文章&#xff0c;大概率你已经收藏了50个GitHub仓库&#xff0c;却连一个完整的RAG系统都没跑通。承认一个事实&#xff1a;你现在走的弯路&#xff0c;就是别人3年前走过的。 我做了10年推荐算法&#xff0c;见过太多技术人在新浪潮面前的焦虑。大模型这波浪潮&…...

Nanbeige4.1-3B参数详解与性能实测:SFT+RL增强版小模型效果深度解析

Nanbeige4.1-3B参数详解与性能实测&#xff1a;SFTRL增强版小模型效果深度解析 1. 引言&#xff1a;小模型也能有大智慧 最近在开源社区里&#xff0c;有一个小模型悄悄火了起来——Nanbeige4.1-3B。你可能在想&#xff0c;现在动辄几十亿、几百亿参数的大模型满天飞&#xf…...

深度学习项目训练环境模型即服务:训练完直接导出ONNX,无缝对接Flask/FastAPI

深度学习项目训练环境模型即服务&#xff1a;训练完直接导出ONNX&#xff0c;无缝对接Flask/FastAPI 1. 环境准备与快速上手 深度学习项目开发最头疼的就是环境配置问题。不同的框架版本、CUDA版本、Python版本&#xff0c;再加上各种依赖库&#xff0c;光是配环境就能耗掉大…...

Qwen1.5-1.8B-GPTQ-Int4开源协作实践:GitHub Issue管理、PR审核、CI/CD流水线搭建

Qwen1.5-1.8B-GPTQ-Int4开源协作实践&#xff1a;GitHub Issue管理、PR审核、CI/CD流水线搭建 1. 项目概述与价值 通义千问1.5-1.8B-Chat-GPTQ-Int4是一个经过量化的轻量级语言模型&#xff0c;专门针对资源受限环境优化。这个模型基于Transformer架构&#xff0c;采用了SwiG…...

神经符号AI:让机器人“想”得更清楚,“做”得更精准

神经符号AI&#xff1a;让机器人“想”得更清楚&#xff0c;“做”得更精准 引言 在机器人迈向通用智能的道路上&#xff0c;一个核心挑战是如何让其既能理解复杂抽象的任务目标&#xff0c;又能适应开放动态的真实环境。纯符号AI擅长逻辑推理与规划&#xff0c;但“不接地气”…...

智能组合实体员中的树形结构管理与遍历算法

智能组合实体中的树形结构管理与遍历算法 在人工智能与大数据时代&#xff0c;智能组合实体&#xff08;如知识图谱、组织结构或自动化决策系统&#xff09;的高效管理离不开树形结构的支持。树形结构以其清晰的层次关系和高效的遍历能力&#xff0c;成为复杂数据组织的重要工…...

Echarts + China.js 实现中国地图数据可视化实战

1. 快速上手Echarts与China.js 最近在做一个疫情数据展示项目时&#xff0c;我发现Echarts配合China.js做中国地图可视化简直不要太方便。记得第一次接触这个组合时&#xff0c;被网上的各种教程绕得晕头转向&#xff0c;今天我就把踩过的坑都总结出来&#xff0c;让你10分钟就…...

玩转OpenClaw:主配置文件参数详解指南手册

配置文件概述 OpenClaw 使用 JSON / JSON5 格式的配置文件来管理系统所有组件的设置。配置文件采用分层结构,支持灵活的配置覆盖和环境变量注入。 主要特性 JSON5 支持:支持注释、尾随逗号、单引号等扩展语法 环境变量:可通过 env 字段或者 .env文件注入环境变量 配置合并…...

【译】 如何使用 .NET MAUI 构建 Android 小部件

▲ 点击上方“DotNet NB”关注公众号回复“1”获取开发者路线图学习分享 丨作者 / 郑 子 铭 这是DotNet NB 公众号的第239篇原创文章原文 | Toine de Boer翻译 | 郑子铭这是Toine de Boer的客座博文。这篇博客将探讨上一篇关于iOS 小部件的博客中创建的交互式小部件的 Andro…...

AgentCPM研报助手应用指南:如何用它高效完成课题研究与论文写作

AgentCPM研报助手应用指南&#xff1a;如何用它高效完成课题研究与论文写作 1. 为什么选择本地研报生成工具&#xff1f; 在学术研究和商业分析领域&#xff0c;撰写深度报告是每个研究者必须面对的任务。传统流程通常包括&#xff1a; 收集和阅读大量文献资料整理数据并构建…...