Go语言之路————并发
Go语言之路————并发
- 前言
- 协程
- 管道
- Select
- sync
- WaitGroup
- 锁
前言
- 我是一名多年Java开发人员,因为工作需要现在要学习go语言,Go语言之路是一个系列,记录着我从0开始接触Go,到后面能正常完成工作上的业务开发的过程,如果你也是个小白或者转Go语言的,希望我这篇文章对你有所帮助。
- 有关go其他基础的内容的文章大家可以查看我的主页,接下来主要就是把这个系列更完,更完之后我会在每篇文章中挂上连接,方便大家跳转和复习。
协程
在学go之前,大家肯定听说过go底层天然支持并发,相信这也是很多人选择学习这款语言的原因之一,那么它到底怎么个天然法,怎么个支持,下面我就一一道来。
Goroutine(轻量级线程),正如标题一样,它也叫做协程,它是go的并发执行单元,是一种比线程更加轻量级的单位,创建一个协程非常简单,只需要用到一个关键词:go,go后面一定要更一个函数:
func main() {go func() {fmt.Print(1)}()
}
我这里用一个go启动一个匿名函数,如果你copy这个代码去执行,你会发现控制台没有任何打印,因为协程就跟Java的线程一样,它是并发去执行的,当我们的main方法跑完的时候,如果协程未执行,那么 整个程序都会关掉,就没有任何输出了。
那怎样让它正常输出呢?聪明的同学肯定会想到,让main线程沉睡一下不就行了,我们来看看代码:
func main() {go func() {fmt.Print(1)}()time.Sleep(1 * time.Second)
}控制台打印:1
由此可见,让主线程沉睡确实可以做到这点,那么我就要提出下一个问题了,如果有多个协程呢?看看下面代码:
func main() {for i := 0; i < 10; i++ {go fmt.Println(i)}time.Sleep(1 * time.Second)
}
当把这段代码执行后,你会发现每次执行的结果都是不一样的,这也引出了协程的一个特性,那就是执行的时候是无序的,那有啥方法解决吗,我们先用上面的sleep看能否解决:
每次执行协程前,我们都让它沉睡一秒,然后主线程沉睡十秒
func main() {for i := 0; i < 10; i++ {time.Sleep(1 * time.Second)go fmt.Println(i)}time.Sleep(10 * time.Second)
}
执行后的结果:
0
1
2
3
4
5
6
7
8
9
目前来看,是做到了,但是这个方法太笨了,有啥办法可以优雅的解决吗,当然,go提供了管道、信号量、上下文、锁等各种工具来辅助开发者进行并发编程。
管道
管道:channel,官方对它的解释:Do not communicate by sharing memory; instead, share memory by communicating.
我用白话文在翻译一次:它的作用就是解决协程之间的通信的,数据传输或者共享的。
一个通道,用chan来定义,定义的时候必须要指定它存的数据类型:
var ch chan int
此时的管道还没初始化,是不能使用的,在go中,初始化一个管道,有且只有一个办法,那就是make关键词,make关键词提供一个额外参数:缓冲区
var ch = make(chan int, 1)
这里就是用make创建了一个缓冲区为1的管道,先看看使用:
func main() {var ch = make(chan int, 1)ch <- 1println(<-ch)
}
输出:1
结合例子,说一下管道的输出和输出:<-,没错就是用箭头表示,箭头的指向表示数据流向,a <- 1,表示把1发到a,<- a,表示从a读取数据
如何理解缓冲区:可以理解为Java中线程池中的阻塞队列,往管道中发送的数据会先存到缓冲区,然后才会被读取,如果一个管道没有缓冲区,那么发送信息后需要立马有读取的操作,否则程序就会阻塞,我们通过下面例子来看:
func main() {var ch = make(chan int)ch <- 1<-ch
}
我们创建一个没有缓冲区的管道,像管道里面输入1,马上再读取。看似人畜无害的代码,执行起来确是这个结果:deadlock
fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan send]:
main.main()D:/goland/workspace/test/main.go:5 +0x2dProcess finished with the exit code 2
那读者又会想了,既然这样,那岂不是所有的管道创建都需要缓冲区。其实不然,如果我们通过协程去输入就能正常输出:
func main() {var ch = make(chan int)go func() {ch <- 1}()println(<-ch)
}
输出:1
思考:为啥有协程的参与就能正常读写?我们回到缓冲区的本质,它是存数据的缓冲的,如果我们没有缓冲区,那么证明这个管道是没办法存数据的,就意味着,我这边写了,必须马上有人读,但是通过同步操作是实现不了的,有协程异步来操作才可行。
注意:每个管道用完后需要我们手段关闭,直接调用系统提供的close方法,一个管道只能close一次,多次close会报错。
func close(c chan<- Type)
但是通常,我们建议把通道的关闭结合defer来用:
func main() {var ch = make(chan int)go func() {ch <- 1defer close(ch)}()println(<-ch)
}
注意点,除了同步读写无缓冲管道会造成堵塞之外,下面几种情况也会造成deadlock:
- 缓冲区满了继续噻数据:
缓冲区大小为1,写入一个后满了没读,继续写func main() {var ch = make(chan int, 1)defer close(ch)ch <- 1ch <- 1println(<-ch) }
- 有缓冲区,但是数据为空
func main() {// 创建的有缓冲管道intCh := make(chan int, 1)defer close(intCh)// 缓冲区为空,阻塞等待其他协程写入数据<-intCh }
- 管道未初始化
func main() {var intCh chan intintCh <- 1 }
管道数据除了一个个读之外,我们还可以用for range来遍历一个管道:
func main() {intCh := make(chan int, 10)go func() {for i := 0; i < 10; i++ {intCh <- i}}()for ch := range intCh {println(ch)}
}
看看输出:
0
1
2
3
4
5
6
7
8
9
fatal error: all goroutines are asleep - deadlock!goroutine 1 [chan receive]:
main.main()D:/goland/workspace/test/main.go:10 +0xa8
在输出之后出现了阻塞,这是因为for range会一直去读写管道中的数据,当管道中数据为空时就会死锁,直到有其他协程向管道写入数据才会解除,所以我们代码改一下,在写入数据完毕后就关闭管道:
func main() {intCh := make(chan int, 10)go func() {for i := 0; i < 10; i++ {intCh <- i}close(intCh)}()for ch := range intCh {println(ch)}
}
最后再补充一个知识点,管道的读取其实是有返回值的:
v, ok := <-intCh
第一个是值,第二个是个bool代表是否读取成功:
func main() {intCh := make(chan int, 10)go func() {intCh <- 1}()a, ok := <-intChprintln(a, ok)
}输出:1 true
Select
在 Go 中,select 是一种管道多路复用的控制结构,某一时刻,同时监测多个元素是否可用,在这里我们可以用来检测多个管道:
func main() {ch1 := make(chan int, 10)ch2 := make(chan int, 10)ch3 := make(chan int, 10)defer func() {close(ch1)close(ch2)close(ch3)}()select {case i := <-ch1:fmt.Println("ch1 is ", i)case j := <-ch2:fmt.Println("ch2 is ", j)case k := <-ch3:fmt.Println("ch3 is ", k)default:fmt.Print("检测失败")}
}
创建三个管道,然后用select分别去监测三个管道的数据,然后doSomething,让我们没有往管道输入任何数据的时候,默认输出检测失败,我们在select前往ch1输入一个数据看看:
func main() {ch1 := make(chan int, 10)ch2 := make(chan int, 10)ch3 := make(chan int, 10)defer func() {close(ch1)close(ch2)close(ch3)}()ch1 <- 1select {case i := <-ch1:fmt.Println("ch1 is ", i)case j := <-ch2:fmt.Println("ch2 is ", j)case k := <-ch3:fmt.Println("ch3 is ", k)default:fmt.Print("检测失败")}
}输出:ch1 is 1
sync
讲到了并发,怎么能离开锁,go的sync包下面提供了很多锁相关的工具类,就类似于Java的juc包,我们下面简单说点常用的。
WaitGroup
WaitGroup 即等待执行,它的方法只有三个,使用起来也非常简单:
- Add:添加一个计数器,表示总数
- Done:每调用一次计数器减1
- Wait:如果计数器不为0,则等待
还记得我们文章开头提到的例子吗,就是在main线程中使用了协程,协程还未执行但是main已经结束了,当时我们用的是sleep方法,现在我们看看怎么用WaitGroup去解决这个问题:
先看看原例子:
func main() {println("start")go func() {println("doSomething")}()println("end")
}
再看看解决后的:
var waitGroup sync.WaitGroupfunc main() {println("start")waitGroup.Add(1)go func() {println("doSomething")waitGroup.Done()}()waitGroup.Wait()println("end")
}看看输出:
start
doSomething
end
锁
go中常用的锁有两个:
- 互斥锁:sync.Mutex
- 读写锁:sync.RWMutex
互斥锁sync.Mutex ,实现了Locker 接口,它的用法非常简单,就三个:
func (m *Mutex) Lock() {m.mu.Lock()
}func (m *Mutex) TryLock() bool {return m.mu.TryLock()
}func (m *Mutex) Unlock() {m.mu.Unlock()
}
我们先来看看互斥锁Mutex,下面我来模拟一个经典的场景,就是不同线程对共享数据操作,让我们看看不用锁的情况下,会不会得到正确结果:
var wait sync.WaitGroup
var count = 0func main() {wait.Add(10)for i := 0; i < 10; i++ {go func(data *int) {// 模拟访问耗时time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))// 访问数据,这里必须要用temp当前数据存起来temp := *data// 模拟计算耗时time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))// 修改数据*data = temp + 1fmt.Println(*data)wait.Done()}(&count)}wait.Wait()fmt.Println("最终结果", count)
}
运行起来发现,每次的输出都不一样,跟Java一样,多线程对共享数据的修改是不安全的,必须要加锁
1
1
2
1
1
1
1
1
1
3
最终结果 3
下面我们改进一下代码,将同步代码用互斥锁包起来,类似于Java的同步代码块:
var lock sync.Mutex
var wait sync.WaitGroup
var count = 0func main() {wait.Add(10)for i := 0; i < 10; i++ {go func(data *int) {lock.Lock()// 模拟访问耗时time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))// 访问数据temp := *data// 模拟计算耗时time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))// 修改数据*data = temp + 1lock.Unlock()fmt.Println(*data)wait.Done()}(&count)}wait.Wait()fmt.Println("最终结果", count)
}
go的互斥锁很简单,用的时候就调用lock()方法,解锁就调用unlock()方法,看看输出:
1
2
3
4
5
6
7
8
9
10
最终结果 10Process finished with the exit code 0
读写锁和互斥锁一样,只是说读写锁的精度更高一点,可以根据读多写少,或者读少写多的情况来判断,它同样实现了Locker接口,只是方法多一些,读写锁内部的读和写是互斥锁,并不是说有两个锁
// 加读锁
func (rw *RWMutex) RLock()// 尝试加读锁
func (rw *RWMutex) TryRLock() bool// 解读锁
func (rw *RWMutex) RUnlock()// 加写锁
func (rw *RWMutex) Lock()// 尝试加写锁
func (rw *RWMutex) TryLock() bool// 解写锁
func (rw *RWMutex) Unlock()
下面看个读写锁的例子(本例来自官方中文文档):
var wait sync.WaitGroup
var count = 0
var rw sync.RWMutexfunc main() {wait.Add(12)// 读多写少go func() {for i := 0; i < 3; i++ {go Write(&count)}wait.Done()}()go func() {for i := 0; i < 7; i++ {go Read(&count)}wait.Done()}()// 等待子协程结束wait.Wait()fmt.Println("最终结果", count)
}func Read(i *int) {time.Sleep(time.Millisecond * time.Duration(rand.Intn(500)))rw.RLock()fmt.Println("拿到读锁")time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))fmt.Println("释放读锁", *i)rw.RUnlock()wait.Done()
}func Write(i *int) {time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))rw.Lock()fmt.Println("拿到写锁")temp := *itime.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))*i = temp + 1fmt.Println("释放写锁", *i)rw.Unlock()wait.Done()
}
该例开启了 3 个写协程,7 个读协程,在读数据的时候都会先获得读锁,读协程可以正常获得读锁,但是会阻塞写协程,获得写锁的时候,则会同时阻塞读协程和写协程,直到释放写锁,如此一来实现了读协程与写协程互斥,保证了数据的正确性。例子输出如下:
拿到读锁
拿到读锁
释放读锁 0
释放读锁 0
拿到写锁
释放写锁 1
拿到读锁
拿到读锁
拿到读锁
拿到读锁
拿到读锁
释放读锁 1
释放读锁 1
释放读锁 1
释放读锁 1
释放读锁 1
拿到写锁
释放写锁 2
拿到写锁
释放写锁 3
最终结果 3Process finished with the exit code 0
OK 上面就是go中并发的一些常用案例,不多,但是一定是最常用的,掌握了这些你就可以去深入扩展了。
相关文章:
Go语言之路————并发
Go语言之路————并发 前言协程管道SelectsyncWaitGroup锁 前言 我是一名多年Java开发人员,因为工作需要现在要学习go语言,Go语言之路是一个系列,记录着我从0开始接触Go,到后面能正常完成工作上的业务开发的过程,如…...
python的家教课程管理系统
目录 技术栈介绍具体实现截图系统设计研究方法:设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示 技术栈介绍 Django-SpringBoot-php-Node.js-flask 本课题的研究方法和研究步骤基本合理,难度适中…...
0x08.Redis 支持事务吗?如何实现?
回答重点 Redis 支持事务,但它的事务与 MySQL 等关系型数据库的事务有着本质区别。MySQL 中的事务严格遵循 ACID 特性,而 Redis 中的事务主要保证的是命令执行的原子性和隔离性,即所有命令在一个不可分割的操作中顺序执行,不会被其他客户端的命令请求所打断。 最关键的区…...
互联网应用的安全防线-身份证实名认证api-身份证三要素验证
随着联网技术的普及,互联网应用已深度渗透人们的生活,从购物下单到社交互动,从金融理财到在线教育,每一次的联网互动都隐藏着一个关乎安全与信任的“隐形卫士”-身份证实名认证接口功能。它如同数字世界的“电子身份证”ÿ…...
本地跑通vue-element-admin项目
GitHub - PanJiaChen/vue-element-admin: :tada: A magical vue admin https://panjiachen.github.io/vue-element-admin 通过加速clone到本地 git clone https://gitclone.com/github.com/PanJiaChen/vue-element-admin.git # 进入项目目录 cd vue-element-admin # 安装依赖…...
el-table表格列宽度自适应
需求:表格错误描述列 要求按照内容最大值设置宽度;如果没有值 则设置最小宽度 <el-table-columnv-else-if"item.prop errorDescription":key"item.code":width"flexColumnWidth(errorDescription, tableConfigA.tableDataA…...
Mysql存储过程(附案例)
文章目录 存储过程概述1、基本语法2、变量①、系统变量②、用户自定义变量③、局部变量 3、流程控制语句①、if语句②、参数③、case语句④、while语句⑤、repeat语句⑥、loop语句⑦、cursor游标⑧、handler 4、存储函数 存储过程概述 存储过程是事先经过编译并存储在数据…...
宇树科技申请 “机器人牌照” 商标,剑指机器人领域新高度
近日,据天眼查信息显示,杭州宇树科技有限公司有了一项重大举动,其申请注册了 “机器人牌照”“机牌”“Robot license”“Robot plate” 等商标,国际分类涉及科学仪器、运输工具、广告销售等多个领域,当前商标状态均为…...
计算机图形学基础--Games101笔记(一)数学基础与光栅化
数学基础 向量 点乘,叉乘和投影: 插值 三角形插值 **重心坐标:**我们通过任意点的重心坐标来插值。 V α V A β V B γ V C V\alpha V_A\beta V_B\gamma V_C VαVAβVBγVC。注意重心坐标没有投影不变性,如果插值三…...
Chrome拓展(Chrome Extension)开发定时任务插件
Chrome扩展定时任务插件开发指南 核心实现原理 使用Chrome Alarms API实现定时触发通过Service Worker保持后台运行本地存储保存任务配置 开发步骤 创建manifest文件 (manifest.json) {"manifest_version": 3,"name": "定时任务助手","…...
100G QSFP28 BIDI光模块一览:100G单纤高速传输方案|易天光通信
目录 前言 一、易天光通信100G QSFP28 BIDI光模块是什么? 二、易天光通信100G QSFP28 BIDI光模块采用的关键技术 三、100G QSFP28 BIDI光模块的优势 四、以“易天光通信100G BIDI 40km ER1光模块”为例 五、总结:高效组网,从“减”开始 关于…...
每日Prompt:迷你 3D 建筑
提示词 3D Q版迷你风格,一个充满奇趣的迷你星巴克咖啡馆,外观就像一个巨大的外带咖啡杯,还有盖子和吸管。建筑共两层,大大的玻璃窗清晰地展示出内部温馨而精致的设计:木质的家具、温暖的灯光以及忙碌的咖啡师们。街道…...
从另一个视角理解TCP握手、挥手与可靠传输
本文将深入探讨 TCP 协议中三次握手、四次挥手的原理,以及其保证可靠传输的机制。 一、三次握手:为何是三次,而非两次? 建立 TCP 连接的过程犹如一场严谨的 “对话”,需要经过三次握手才能确保通信双方的可靠连接。 三…...
SearxNG本地搜索引擎
SearxNG 是一个强大、开源的 元搜索引擎(meta search engine),它不会存储用户信息,注重隐私保护,并支持从多个搜索引擎聚合结果,用户可以自建部署,打造一个无广告、可定制的搜索平台。 🔍 什么是 SearxNG? SearxNG 是 Searx 的一个积极维护的分支(fork),意在改进…...
基于支持向量机(SVM)的P300检测分类
基于支持向量机(SVM)的P300检测分类MATLAB实现,包含数据预处理、特征提取和分类评估流程: %% P300检测分类完整流程(SVM实现) clc; clear; close all;%% 1. 数据加载与模拟生成(实际应用需替换…...
Oracle学习日记--Oracle中使用单个inert语句实现插入多行记录
目录 前言: 问题现象: 问题分析: 解决方法: 1、insert into ... union all句式 2、insert all into ...select 1 from dual句式 总结: 前言: 最近项目中使用到了Oracle数据库,由于Oracle数…...
利用边缘计算和工业计算机实现智能视频分析
在人工智能和物联网取得重大进步的时代,智能视频分析(IVA)正在通过整合先进的人工智能技术来改变视频监控和分析。这项革命性的技术增强了视觉智能,是关键行业创新解决方案的驱动因素。在本文中,我们将介绍IVA的好处、…...
tomcat一闪而过,按任意键继续以及控制台中文乱码问题
问题描述 今天在打开tomcat,启动startup.bat程序时 tomcat直接闪退,后面查找资料后发现,可以通过编辑startup.bat文件内容,在最后一行加入pause即可让程序不会因为异常而终止退出 这样方便查看tomcat所爆出的错误: 然后,我明确看到我的tomcat启动程序显示如下的内容,没有明确…...
go 集成base64Captcha 支持多种验证码
base64Captcha 是一个基于 Go 语言开发的验证码生成库,主要用于在 Web 应用中集成验证码功能,以增强系统的安全性。以下是其主要特点和简介: base64Captcha主要功能 验证码类型丰富:支持生成多种类型的验证码,包括纯…...
【数据结构】线性表--栈
【数据结构】线性表--栈 一.什么是栈二.栈的实现1.栈结构定义:2.栈的初始化:3.栈的销毁:4.插入函数:5.删除函数:6.求栈顶元素:7.求数据个数:8.判空: 三.总结 一.什么是栈 栈是一种重…...
基于亚博K210开发板——麦克风录播测试
开发板 亚博K210开发板 实验目的 本次测试主要学习 K210 通过 I2S 接收和发送的功能,麦克风录音,扬声器播放。 实验准备 实验元件 扬声器、麦克风 元件特性 K210 开发板的麦克风同样是使用 I2S 传输数据,只不过麦克风使用的是 I2S…...
操作系统-锁/内存/中断/IO
文章目录 锁自旋锁互斥锁悲观锁和乐观锁 内存管理物理/虚拟内存页表段表虚拟内存布局写时复制copy on writebrk,mmap页面置换算法 中断中断分类中断流程 网络I/OI/O模型服务器处理并发请求 锁 自旋锁 自旋锁是一种基于忙等待(Busy-Waiting)…...
割点与其例题
割点 定义: 若一个点在图中被去掉后,图的连通块个数增加,那么这个点就被称为“割点”。如下图所示红点。 定义说白了就是若去掉一个点,图被“断开”的点称为割点。 朴素算法: 枚举每个点 u。遍历图,如果…...
CSS实现文本自动平衡text-wrap: balance
不再有排版孤行和寡行 我们都知道那些标题,最后一个单词换行并单独站在新行上,破坏了视觉效果,看起来很奇怪。当然,有老式的 手动换行或将内容分成不同部分。但您听说过text-wrap: balance吗? 通过应用text-wrap: bal…...
【未完】【GNN笔记】EvolveGCN:Evolving Graph Convolutional Networks for Dynamics Graphs
Evolving Graph Convolutional Networks for Dynamics Graphs 视频链接:《图神经网络》 相关系列: 《Dynamic Graph的分类》《动态图网络之Dynamic Self-Attention Network》 文章目录 Evolving Graph Convolutional Networks for Dynamics Graphs一、…...
【愚公系列】《Manus极简入门》042-投资策略分析师:“投资智慧导航”
🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! …...
《AI大模型应知应会100篇》第65篇:基于大模型的文档问答系统实现
第65篇:基于大模型的文档问答系统实现 📚 摘要:本文详解如何构建一个基于大语言模型(LLM)的文档问答系统,支持用户上传 PDF 或 Word 文档,并根据其内容进行智能问答。从文档解析、向量化、存储到…...
P1439 【模板】最长公共子序列
P1439 【模板】最长公共子序列 - 洛谷 题目描述 给出1, 2, …, n的两个排列P1和P2,求它们的最长公共子序列。 输入格式 第一行是一个数n。 接下来两行,每行为n个数,为自然数1, 2, …, n的一个排列。 输出格式 一个数,即…...
LLaMA-Factory:环境准备
一、硬件和系统 操作系统: Ubuntu 24.04.2 LTS(64位)GPU: NVIDIA RTX 4090 笔记本 GPU,16GB显存CPU: 建议高性能多核 CPU(如 Intel i7/i9 或 AMD Ryzen 7/9)以支持数据预处理,我的是32核。RAM: 至少 32GB&…...
polarctf-web-[rce1]
考点: (1)RCE(exec函数) (2)空格绕过 (3)执行函数(exec函数) (4)闭合(ping命令闭合) 题目来源:Polarctf-web-[rce1] 解题: 这段代码实现了一个简单的 Ping 测试工具,用户可以通过表单提交一个 IP 地址,服务器会执…...
AI实践用例---日程规划(通用日程管理文件ICS)灵感踩坑日常
我是一位践行独立开发者之路的菜鸟开发者。 由于执行力较差,常常有很多想法但是很多时候没有去践行。 所以我有了让大模型为我生成日程安排的想法,这确实可以,很简单。只需要将你的想法告诉ai就行了。 例如: 发给AI的提示词: 我想你帮我对,嗯,未来的一年做一个嗯,大…...
MySQL 8.0 OCP 1Z0-908 121-130题
Q121.Examine these statements and output: mysql> GRANT PROXY ON accountinglocalhost TO ’ ‘ ‘%’; mysql> SELECT USER(), CURRENT_USER(), proxy_user; --------------------------------------------------------- |USER() | CURRENT_USER() | proxy_user I | …...
InfluxDB 2.7 连续查询实战指南:Task 替代方案详解
InfluxDB 2.7 引入了 Task 功能,作为连续查询(CQ)的现代替代方案。本文详细介绍了如何使用 Task 实现传统 CQ 的功能,包括语法解析、示例代码、参数对比以及典型应用场景。通过实际案例和最佳实践,帮助开发者高效迁移并…...
计算机网络 : Socket编程
计算机网络 : Socket编程 目录 计算机网络 : Socket编程引言1.UDP网络编程1.1 网络地址与端口转换函数1.2 本地环回1.3 EchoServer1.4 DictServer1.5 DictServer封装版1.6 简单聊天室 2.TCP网络编程2.1 TCP Socket API详解2.2 Echo Server2.3 Echo Serve…...
C++动态内存分配
内存管理 1.代码段(Code Segment / Text Segment)常量区2. 数据段(Data Segment)静态区3. BSS 段(未初始化数据段)4. 堆(Heap)5. 栈(Stack)6. 内存映射段&…...
git版本控制学习
1.环境搭配 2.Linux常用指令 cd:更改目录cd..回到上一级目录pow:显示当前所在的目录路径li(||):列出当前目录所有文件,只不过||例出的内容更为详细touch:新建一个文件夹如touch index.js就会在当前目录下新建一个index.js文件rm:删除一个文件,rm index.js 就会把in…...
在MYSQL中导入cookbook.sql文件
参考资料: GitHub 项目:svetasmirnova/mysqlcookbook CSDN 博客:https://blog.csdn.net/u011868279/category_11645577.html 建库: mysql> use mysql Reading table information for completion of table and column names …...
安科瑞AcrelEMS3.0企业微电网智慧能源平台-安科瑞 蒋静
1、平台介绍 Acrel-EMS3.0 智慧能源平台是针对企业微电网的能效管理平台,满足江苏省《新型电力负荷管理系统数据接入规范》的技术架构,可通过云云互联方式接受电力平台的调度指令和策略下发,支持作为微网调度子系统或子平台。 2、解决方案 …...
5G-A和未来6G技术下的操作系统与移动设备变革:云端化与轻量化的发展趋势
目录 5G技术带来的革命性变革 云端化操作系统的实现路径 完全云端化模式 过渡性解决方案 未来操作系统的发展方向 功能架构演进 安全机制强化 移动设备的形态变革 终端设备轻量化 物联网设备简化 实施挑战与应对策略 技术挑战 商业模式创新 总结与展望 5G技术作为…...
TensorFlow/Keras实现知识蒸馏案例
创建一个“教师”模型(一个稍微复杂点的网络)。创建一个“学生”模型(一个更简单的网络)。使用“软标签”(教师模型的输出概率)和“硬标签”(真实标签)来训练学生模型。 import tens…...
能源数字化转型关键引擎:Profinet转Modbus TCP网关驱动设备协同升级
在工业自动化的世界中,ModbusTCP和Profinet是两个非常重要的通讯协议。ModbusTCP以其开放性和易用性,被广泛应用于各种工业设备中;而Profinet则以其高效性和实时性,成为了众多高端设备的首选。然而,由于这两种协议的差…...
大模型的实践应用43-基于Qwen3(32B)+LangChain框架+MCP+RAG+传统算法的旅游行程规划系统
大家好,我是微学AI,今天给大家介绍一下大模型的实践应用43-基于Qwen3(32B)+LangChain框架+MCP+RAG+传统算法的旅游行程规划系统。本报告将阐述基于大模型Qwen3(32B)、LangChain框架、MCP协议、RAG技术以及传统算法构建的智能旅游行程规划系统。该系统通过整合多种技术优势,实…...
【Unity】用事件广播的方式实现游戏暂停,简单且实用!
1.前言 在做Unity项目的时候,要考虑到“游戏暂停”的功能,最直接的办法是修改游戏的Time.TimeScale 0f。但是这种方式的影响也比较大,因为它会导致游戏中很多程序无法正常运行。 于是我就有了一个想法,在游戏中想要暂停的对象&…...
二维数组以及C99中的变长数组(如何在VS2022中使用苹果的clang编译器)
一、二维数组的创建 1.1 二维数组的概念 在上一篇文章中所写的称为一维数组,数组的元素都是内置类型的,如果我们把一维数组作为数组的元素,这时候就是二维数组,二维数组作为数组元素的数组被称为三维数组,二维数组以…...
影楼精修-肤色统一算法解析
注意:本文样例图片为了避免侵权,均使用AIGC生成; 本文介绍影楼精修中肤色统一算法的实现方案,并以像素蛋糕为例,进行分析说明。 肤色统一就是将人像照片中皮肤区域的颜色进行统一,看起来颜色均匀一致&…...
mac的Cli为什么输入python3才有用python --version显示无效,pyenv入门笔记,如何查看mac自带的标准库模块
根据你的终端输出,可以得出以下结论: 1. 你的 Mac 当前只有一个 Python 版本 系统默认的 Python 3 位于 /usr/bin/python3(这是 macOS 自带的 Python)通过 which python3 确认当前使用的就是系统自带的 Pythonbrew list python …...
城市内涝监测预警系统守护城市安全
一、系统背景 城市内涝是指由于强降水或连续性降水超过城市排水能力,导致城市内产生积水灾害的现象。随着气候变化和城市化进程的加快,城市内涝现象愈发频繁和严重。传统的城市排水系统已难以满足当前的城市排水需求,特别是在暴雨等极端天气条…...
ThinkPad X250电池换电池芯(理论技术储备)
参考:笔记本电池换电芯的经验与心得分享 - 经典ThinkPad专区 - 专门网 换电池芯,需要克服以下问题: 1 拆电池。由于是超声波焊接,拆解比较费力,如果暴力撬,有可能导致电池壳变形... 2 替换电池芯的时候如…...
2025第三届盘古初赛(计算机部分)
前言 比赛的时候时间不对,打一会干一会,导致比赛时候思路都跟不上,赛后简单复现一下,希望大家批批一下 计算机取证 1、分析贾韦码计算机检材,计算机系统Build版本为?【标准格式:19000】 183…...
qtc++ qdebug日志生成
本文介绍了将qdebug注册到日志系统,这样qdebug打印的信息将记录在日志文本文件,方便观看程序运行中的历史信息,但是需要注意的是,注册后qdebug的信息将不会打印在qtcreator的输出中,所以作者建议,在开发的时…...