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

go的通信Channel

一、channel是什么

1.一种通信机制

channel是goroutine与goroutine之间数据通信的一种通信机制。一般都是2个g及以上一起工作。

channel与关键字range和select紧密相关。

二、channel的结构

go源码:GitHub - golang/go: The Go programming language

src/runtime/chan.go

type hchan struct {qcount   uint           // total data in the queue 队列中当前元素计数,满了就=dataqsizdataqsiz uint           // size of the circular queue 环形队列大小(缓存大小)buf      unsafe.Pointer // points to an array of dataqsiz elements 指向任意类型的指针elemsize uint16  //元素大小closed   uint32  //是否关闭,0-未关闭,1-已关闭timer    *timer // timer feeding this chan //定时器elemtype *_type // element type //元素类型sendx    uint   // send index //发送索引recvx    uint   // receive index //结束索引recvq    waitq  // list of recv waiters //接收等待队列(<-ch)sendq    waitq  // list of send waiters //发送等待队列(ch<-)// lock protects all fields in hchan, as well as several// fields in sudogs blocked on this channel.//// Do not change another G's status while holding this lock// (in particular, do not ready a G), as this can deadlock// with stack shrinking.lock mutex //锁,保护hchan中的所有字段
}type waitq struct { //等待队列,sudog双向链表结构first *sudog //(伪g)表示等待列表中的g,例如在一个通道上用于发送/接收的glast  *sudog //用acquireSudog分配,releaseSudog释放

1.特点

结构体上可以记住channel的一些比如说

(1)lock 锁:操作channel是互斥的。先获取锁,操作channel,释放锁

(2)elemtype类型:创建的时候必须指定类型(大小可指定,如ch := make(chan int,10))

(3)waitq队列:FIFO先进先出队列,即通道,能通过任意类型(unsafe.Pointer)的数据,(sudog)双向链表的g

(4)dataqsiz通道容量:有值=有缓冲通道,没值=无缓冲通道

(5)qcount通道元素计数:当前通道内的元素个数总数

(6)接受和发送:通信,有人发还要有人收,意味必须2个g及以上的成员一起工作

(7)timer定时器:定时可对channel做特殊操作

(8)closed关闭:写(发送)已关闭通道会panic,读(接收)已关闭通道立刻返回:true,false

三、channel的创建

1.make、var

make(chan类型 元素类型,缓冲容量大小),make初始化channel的值是nil

var chan类型 元素类型:var 只是声明,没初始化,直接操作会报错

func Test_2(t *testing.T) {ch1 := make(chan int)       //双向ch11 := make(chan int, 10)  //双向,带缓冲容量10ch2 := make(chan<- int)     //只写ch22 := make(chan int, 10)  //只写,带缓冲容量10ch3 := make(<-chan float64) //只读ch33 := make(chan int, 10)  //只读,带缓冲容量10//go1.17_spec.html//chan T          // can be used to send and receive values of type T//chan<- float64  // can only be used to send float64s//<-chan int      // can only be used to receive intsvar ch4 chan int//通道是引用类型,通道类型的空值是nil。g.Dump(ch1, ch11, ch2, ch22, ch3, ch33, ch4)//打印//<chan int>//<chan int>//<chan<- int>//<chan int>//<<-chan float64>//<chan int>//<chan int>
}

2.chan类型:

chan类型分3种:双向读写、单向写、单向读

ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" )=(双向|单向发送(写)|单向接收(读))

单向只写通道:操作读会报错。

如使用场景,上下文:src/context/context.go的Context,

type Context interface {
...// a Done channel for cancellation.Done() <-chan struct{}
...}

单向只读通道:操作写会报错

如使用场景,信号量:src/os/signal/signal.go的handlers,

var handlers struct {sync.Mutex// Map a channel to the signals that should be sent to it.m map[chan<- os.Signal]*handler...
}type stopping struct {c chan<- os.Signalh *handler
}

3.元素类型:

任意数据类型,如:int,float64,bool,map...

4.缓冲容量

第二个参数给定数量,如10

无缓冲通道:ch := make(chan int);

有缓冲通道:ch := make(chan int,10)

四、向channel写数据

channel的发送要注意区分【有缓冲容量】和【无缓冲容量】

1.正常发送

默认情况下,发送和接收会一直阻塞着,直到另一方准备好。使用:ch <- i

不管是【有缓冲容量】和【无缓冲容量】的通道,只有有g在接收,其他g就能正常发

func Test_send1(t *testing.T) {ch := make(chan int) //双向//开启goroutine将1~5的数发送到ch中go func() {for i := 1; i <= 5; i++ {fmt.Println("写入ch 元素:", i)ch <- i}close(ch) //写完,关闭通道}()//在主goroutine中从ch中接收值打印for i := range ch {fmt.Println("读取ch 结果:", i)}//写入ch 元素: 1//写入ch 元素: 2//读取ch 结果: 1//读取ch 结果: 2//写入ch 元素: 3//写入ch 元素: 4//读取ch 结果: 3//读取ch 结果: 4//写入ch 元素: 5//读取ch 结果: 5//主goroutine和goroutine读写互斥,相互竞争锁。直到通道关闭主程结束
}

2.异常发送【无缓冲】

没g在接收:无缓冲,其他g不能发,直接阻塞

注意:select是非阻塞发送,会直接返回false

func Test_send2(t *testing.T) {ch := make(chan int) //双向//开启goroutine将1~5的数发送到ch中go func() {for i := 1; i <= 5; i++ {fmt.Println("写入ch 元素:", i)ch <- i}close(ch) //写完,关闭通道}()//写入ch 元素: 1//无缓存通道:没人接收,尝试发送1时,g被阻塞
}

3.异常发送【有缓冲】

没g在接收:有缓冲,其他g能发缓冲容量个数,再阻塞

有缓存通道,容量5,能先发5个,第6个阻塞

func Test_send4(t *testing.T) {ch := make(chan int, 5) //双向//开启goroutine将1~5的数发送到ch中go func() {for i := 1; i <= 10; i++ {fmt.Println("写入ch 元素:", i)ch <- i}close(ch) //写完,关闭通道}()//写入ch 元素: 1//写入ch 元素: 2//写入ch 元素: 3//写入ch 元素: 4//写入ch 元素: 5//写入ch 元素: 6//无缓存通道:没人接收,前5个元素成功发送,尝试发送6时,g才被阻塞
}

4.已关闭发送

已关闭的channel,操作发送会panic

func Test_send3(t *testing.T) {ch := make(chan int) //双向close(ch)            //关闭通道ch <- 1//在主goroutine中从ch中接收值打印for i := range ch {fmt.Println("读取ch 结果:", i)}//panic: send on closed channel
}

5.发送源码:

ch <- i

//发送入口:参数(通道,数据指针)
func chansend1(c *hchan, elem unsafe.Pointer) {chansend(c, elem, true, getcallerpc())
}
func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool {//(1)如果通道==nil了,并且block==ture,会调用gopark()函数,使当前的g休眠//从而导致了:all goroutines are asleep - deadlock!if c == nil {if !block {return false}gopark(nil, nil, waitReasonChanSendNilChan, traceBlockForever, 2)throw("unreachable")}...lock(&c.lock)if c.closed != 0 {//(2)如果通道关闭了,不允许发送,直接panicunlock(&c.lock)panic(plainError("send on closed channel"))}...if sg := c.recvq.dequeue(); sg != nil { //(3)接收队列有gsend(c, sg, ep, func() { unlock(&c.lock) }, 3)return true}if c.qcount < c.dataqsiz { //(4)接收队列没有g,看有缓冲容量且还没满,往缓冲中发...}...gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanSend, traceBlockChanSend, 2) //(5)阻塞...
}
//有接收的g,直接发送
func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {...sendDirect(c.elemtype, sg, ep)...
}
//将数据直接写入到接收方的执行栈
func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) {...memmove(dst, src, t.Size_)...
}
// memmove从"from"拷贝n个字节到"to"
func memmove(to, from unsafe.Pointer, n uintptr)

发送数据大概过程:

(1)判断channel是否nil,nil且bolck=true,阻塞当前发送g,等待接收方接收数据

(2)获取锁,如果通道关闭了,不允许发送,直接panic

(3)如果当前有接收队列有g在接收,直接调send()函数发送,返回true

(4)接收队列没有g,看有缓冲容量且还没满,往缓冲中发,返回true

(5)找不到接收的g,且缓冲容量也满了,阻塞当前发送的g,等待接收方接收数据

(6)唤醒等待执行的其他g

尤其注意:通道是nil的情况,直接写数据,会发生all goroutines are asleep - deadlock!的情况

func Test_deadlock1(t *testing.T) {// 未初始化的channel,直接写死锁var ch chan intch <- 1//fatal error: all goroutines are asleep - deadlock!// 初始化无缓冲的channel,直接写死锁ch := make(chan int)ch <- 1//fatal error: all goroutines are asleep - deadlock!
}

四、向channel读数据

1.正常读取:

channel读取数据一般用range来遍历读。

也可以用for循环来遍历,channel的recvq和sendq本质是一个双向链表。

跟发送类似,不管是【有缓冲容量】和【无缓冲容量】的通道,只要有g在接收(接收先于发送),其他g就能正常发

func Test_send1(t *testing.T) {ch := make(chan int) //双向//开启goroutine将1~5的数发送到ch中go func() {for i := 1; i <= 5; i++ {fmt.Println("写入ch 元素:", i)ch <- i}close(ch) //写完,关闭通道}()//在主goroutine中从ch中接收值打印for i := range ch {fmt.Println("读取ch 结果:", i)}//写入ch 元素: 1//写入ch 元素: 2//读取ch 结果: 1//读取ch 结果: 2//写入ch 元素: 3//写入ch 元素: 4//读取ch 结果: 3//读取ch 结果: 4//写入ch 元素: 5//读取ch 结果: 5//主goroutine和goroutine读写互斥,相互竞争锁。直到通道关闭主程结束
}

2.异常读取【死锁】

(1)读完未关闭的channel会造成死锁

func Test_read8(t *testing.T) {ch := make(chan int) //双向//开启goroutine将1~5的数发送到ch中go func() {for i := 1; i <= 5; i++ {fmt.Println("写入ch 元素:", i)ch <- i}//close(ch) //写完,关闭通道}()//在主goroutine中从ch中接收值打印for i := range ch {fmt.Println("读取ch 结果:", i)}//写入ch 元素: 1//写入ch 元素: 2//读取ch 结果: 1//读取ch 结果: 2//写入ch 元素: 3//写入ch 元素: 4//读取ch 结果: 3//读取ch 结果: 4//写入ch 元素: 5//读取ch 结果: 5//fatal error: all goroutines are asleep - deadlock!
}

同样:如果channel没关闭,一直for循环读,读完之后会报死锁的错误。


func Test_read2(t *testing.T) {ch := make(chan int) //双向for i := 1; i < 9; i++ {v, ok := <-chfmt.Println(v, ok)}
}
func Test_read3(t *testing.T) {ch := make(chan int, 5) //双向for i := 1; i < 9; i++ {v, ok := <-chfmt.Println(v, ok)}
}
func Test_read4(t *testing.T) {var ch chan intfor i := 1; i < 9; i++ {v, ok := <-chfmt.Println(v, ok)}
}

3.已关闭读取

思考:会panic吗?

答案是:不会panic,不影响

已关闭通道,如果有值,返回:值,true

已关闭通道,如果没值,返回:0,false

func Test_read5(t *testing.T) {ch := make(chan int) //双向close(ch)for i := range ch {fmt.Println("读取ch 结果:", i)}//0 false//0 false//0 false//0 false//0 false//0 false//0 false//0 false
}func Test_read6(t *testing.T) {ch := make(chan int, 5) //双向for i := 1; i <= 5; i++ {fmt.Println("写入ch 元素:", i)ch <- i}close(ch)for i := 1; i < 9; i++ {v, ok := <-chfmt.Println(v, ok)}//写入ch 元素: 1//写入ch 元素: 2//写入ch 元素: 3//写入ch 元素: 4//写入ch 元素: 5//1 true//2 true//3 true//4 true//5 true//0 false//0 false//0 false
}

4.读取源码:

v <- ch     ,chanrecv1(c *hchan, elem unsafe.Pointer)

v,ok <-ch ,chanrecv2(c *hchan, elem unsafe.Pointer) (received bool)

//接收程序入口
func chanrecv1(c *hchan, elem unsafe.Pointer) {chanrecv(c, elem, true)
}
func chanrecv2(c *hchan, elem unsafe.Pointer) (received bool) {_, received = chanrecv(c, elem, true)return
}func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {...//(1)如果channel==nil,block==true,调gopart()阻塞当前读取的g//和发送一样,容易造成all g asleep()的问题if c == nil {if !block {return}gopark(nil, nil, waitReasonChanReceiveNilChan, traceBlockForever, 2)throw("unreachable")}...lock(&c.lock)if c.closed != 0 {//(2)通道已关闭,并且没有缓冲值,直接返回true, falseif c.qcount == 0 {...return true, false}} else {if sg := c.sendq.dequeue(); sg != nil {//(3)否则,如果有发送队列在等待,直接调recv进行接收recv(c, sg, ep, func() { unlock(&c.lock) }, 3)return true, true}}//(4)通道未关闭,且缓冲有值,直接读缓冲队列的值if c.qcount > 0 {...return true, true}...gopark(chanparkcommit, unsafe.Pointer(&c.lock), waitReasonChanReceive, traceBlockChanRecv, 2) //(5)通道没关闭又没有发送的g,且缓冲也是空的,则阻塞当前读取的g...releaseSudog(mysg) //(6)唤醒等待执行的其他g...
}
func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {...recvDirect(c.elemtype, sg, ep)...
}
func recvDirect(t *_type, sg *sudog, dst unsafe.Pointer) {...memmove(dst, src, t.Size_)...
}
//memmove从"from"拷贝n个字节到"to"
func memmove(to, from unsafe.Pointer, n uintptr)

(1)如果channel==nil,block==true,调gopart()阻塞当前读取的g

(2)通道已关闭,并且没有缓冲值,直接返回true, false

(3)否则,如果有发送队列在等待,直接调recv进行接收

(4)通道未关闭,且缓冲有值,直接读缓冲队列的值

(5)通道没关闭又没有发送的g,且缓冲也是空的,则阻塞当前读取的g

(6)唤醒等待执行的其他g

读取也要注意:通道是nil的情况,直接读数据,会发生all goroutines are asleep - deadlock!的情况

func Test_deadlock2(t *testing.T) {// 未初始化的channel,直接读死锁var ch chan int<-ch//fatal error: all goroutines are asleep - deadlock!// 初始化无缓冲的channel,直接读死锁ch := make(chan int)val, ok := <-chfmt.Println(val, ok)//  //fatal error: all goroutines are asleep - deadlock!
}

五、channel死锁问题

channel使用不当,很容易造成死锁的问题,死锁的本质是:all goroutines are asleep

1.未关闭channel

通道写完不关闭,容易造成死锁

func Test_deadlock5(t *testing.T) {// 初始化有缓冲的channel,先写后读,读完数据后死锁ch := make(chan int, 5)ch <- 1ch <- 2ch <- 3//range 是阻塞读for v := range ch {fmt.Println(v)}//1//2//3//fatal error: all goroutines are asleep - deadlock!
}

2.已关闭channel

正常使用channel,记得关闭通道

func Test_deadlock5(t *testing.T) {// 初始化有缓冲的channel,先写后读,读完数据后死锁ch := make(chan int, 5)ch <- 1ch <- 2ch <- 3close(ch)//range 是阻塞读for v := range ch {fmt.Println(v)}//1//2//3
}

3.读要先于发 

思考为什么无缓冲 Channel 读要先于发?尝试从源码角度分析,因为无缓存channel的接收方会从发送方栈拷贝数据后,发送方才会被放回调度队列种,等待重新调度,如果一直没有读,发就一直卡住,无法被唤醒

func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
...
recv(c, sg, ep, func() { unlock(&c.lock) }, 3)
...
}//1.c通道
//2.发送方sg发送的值被放入通道中,发送方被唤醒,继续它的快乐之路
//3.接收方接收到的值(当前G)为写入ep
func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) {//无缓冲读if c.dataqsiz == 0 {...if ep != nil {// copy data from sender 接收是直接从发送的栈进行拷贝recvDirect(c.elemtype, sg, ep)}} else {//有缓冲读// 从缓存队列拷贝qp := chanbuf(c, c.recvx)...}gp.param = unsafe.Pointer(sg)...//唤醒g准备执行goready(gp, skip+1)
}func recvDirect(t *_type, sg *sudog, dst unsafe.Pointer) {// dst is on our stack or the heap, src is on another stack.// The channel is locked, so src will not move during this// operation.src := sg.elemtypeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.Size_)//从"from"拷贝n个字节到"to",from是src发送方,to就是dst接受方memmove(dst, src, t.Size_)
}
func memmove(to, from unsafe.Pointer, n uintptr)

4.panic问题

(1)已关闭的通道,再次关闭,会panic

(2)已关闭的通道,写入会panic

五、select

待续

六、总结

1.通道创建类型有3种:双向,只读,只写

2.通道有容量可设:无缓冲通道和有缓冲通道

3.通道读写互斥

4.已关闭通道,写panic,读有值,再关闭panic

5.通道通常需要2个g一起工作

相关文章:

go的通信Channel

一、channel是什么 1.一种通信机制 channel是goroutine与goroutine之间数据通信的一种通信机制。一般都是2个g及以上一起工作。 channel与关键字range和select紧密相关。 二、channel的结构 go源码&#xff1a;GitHub - golang/go: The Go programming language src/runt…...

手写红黑树【数据结构】

手写红黑树【数据结构】 前言版权推荐手写红黑树一、理论知识红黑树的特征增加删除 二、手写代码初始-树结点初始-红黑树初始-遍历初始-判断红黑树是否有效查找增加-1.父为黑&#xff0c;直接插入增加-2. 父叔为红&#xff0c;颜色调换增加-3. 父红叔黑&#xff0c;颜色调换&am…...

[蓝桥杯练习]通电

kruskal做法(加边) #include <bits/stdc.h> using namespace std; int x[10005],y[10005],z[10005];//存储i点的x与y坐标 int bcj[10005];//并查集 struct Edge{//边 int v1,v2; double w; }edge[2000005]; int cmp(Edge a, Edge b){return a.w < b.w;} int find(i…...

安全算法 - 摘要算法

摘要算法是一种将任意长度的数据转换为固定长度字节串的算法。它具有以下特点和应用。 首先&#xff0c;摘要算法能够生成一个唯一且固定长度的摘要值&#xff0c;用于验证数据的完整性和一致性。无论输入数据有多长&#xff0c;生成的摘要值始终是固定长度的&#xff0c;且即…...

操作系统:动静态库

目录 1.动静态库 1.1.如何制作一个库 1.2.静态库的使用和管理 1.3.安装和使用库 1.4.动态库 1.4.1.动态库的实现 1.4.2.动态库与静态库的区别 1.4.3.共享动态库给系统的方法 2.动态链接 2.1.操作系统层面的动态链接 1.动静态库 静态库&#xff08;.a&#xff09;&…...

车载电子电器架构 —— 局部网络管理汇总

车载电子电器架构 —— 局部网络管理汇总 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明…...

网络安全 | 什么是DDoS攻击?

关注WX&#xff1a;CodingTechWork DDoS-介绍 DoS&#xff1a;Denial of Service&#xff0c;拒绝服务。DDoS是通过大规模的网络流量使得正常流量不能访问受害者目标&#xff0c;是一种压垮性的网络攻击&#xff0c;而不是一种入侵手段。NTP网络时间协议&#xff0c;设备需要…...

[Godot] 3D拾取

CollisionObject3D文档 Camera3D文档 CollisionObject3D有个信号_input_event&#xff0c;可以用于处理3D拾取。 Camera3D也有project_position用于将屏幕空间坐标投影到3D空间。 extends Node3D#是否处于选中状态 var selected : bool false #摄像机的前向量 var front : V…...

知识融合:知识图谱构建的关键技术

目录 一、引言二、知识图谱基础2.1 知识表示三元组属性图 2.2 知识抽取实体抽取关系抽取属性抽取 三、知识融合的核心问题3.1 实体识别与链接实体识别实体链接 3.2 重复实体合并方法示例 3.3 关系融合挑战方法示例 四、知识融合技术深度解析4.1 基于规则的方法规则设计原则规则…...

外贸建站:WordPress搭建外贸独立站零基础自建站完整教程(2024)

对于做外贸来说&#xff0c;拥有自己的外贸独立网站真的非常重要。在外贸领域&#xff0c;如今各平台竞争激烈&#xff0c;规则多&#xff0c;成本高&#xff0c;价格战、政策变化快&#xff0c;还存在封店风险等等因素。在这种情况下&#xff0c;拥有外贸独立站就能很好规避上…...

【教程】Kotlin语言学习笔记(五)——Lambda表达式与条件控制

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【Kotlin语言学习】系列文章 第一章 《认识Kotlin》 第二章 《数据类型》 第三章 《数据容器》 第四章 《方法》 第五章 《L…...

C++的并发世界(三)——线程对象生命周期

0.案例代码 先看下面一个例子&#xff1a; #include <iostream> #include <thread>void ThreadMain() {std::cout << "begin sub thread:" << std::this_thread::get_id()<<std::endl;for (int i 0; i < 10; i){std::cout <&…...

SAD法(附python实现)和Siamese神经网络计算图像的视差图

1 视差图 视差图&#xff1a;以左视图视差图为例&#xff0c;在像素位置p的视差值等于该像素在右图上的匹配点的列坐标减去其在左图上的列坐标 视差图和深度图&#xff1a; z f b d z \frac{fb}{d} zdfb​ 其中 d d d 是视差&#xff0c; f f f 是焦距&#xff0c; b b…...

基于DWT(离散小波变换)的图像加密水印算法,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…...

【威胁情报综述阅读3】Cyber Threat Intelligence Mining for Proactive Cybersecurity Defense

【威胁情报综述阅读1】Cyber Threat Intelligence Mining for Proactive Cybersecurity Defense: A Survey and New Perspectives 写在最前面一、介绍二、网络威胁情报挖掘方法和分类A. 研究方法1&#xff09; 第 1 步 - 网络场景分析&#xff1a;2&#xff09; 第 2 步 - 数据…...

在编程中使用中文到底该不该??

看到知乎上有个热门问题&#xff0c;为什么很多人反对中文在编程中的使用&#xff1f; 这个问题有几百万的浏览热度&#xff0c;其中排名第一的回答非常简洁&#xff0c;我深以为然&#xff1a; 在国内做开发&#xff0c;用中文写注释、写文档&#xff0c;是非常好的习惯&…...

PyQt6从入门到放弃

PyQt6从入门到放弃 安装PyQt6 pip install PyQt6# 查看QT和PyQT的版本 from PyQt6.QtCore import QT_VERSION_STR from PyQt6.QtCore import PYQT_VERSION_STR print(QT_VERSION_STR) print(PYQT_VERSION_STR)PyQt6模块 PyQt6类由一系列模块组成包括QtCore、QtGui、QtWidgets…...

PhpWord导入试卷

规定word导入格式 1、[单选题][2024][一般]题目1 A.选项1 B.选项2 C.选项3 D.选项4 答案&#xff1a;D 试题图片&#xff08;上传多媒体图片&#xff09;&#xff1a; 分数&#xff1a;2 答案解析&#xff1a; 2、[多选题][2024][困难]题目2 A.选项1 B.选项2 C.选项3 D.选项4 E…...

C# 运算符重载 之前的小总结

C# 中支持运算符重载&#xff0c;所谓运算符重载就是我们可以使用自定义类型来重新定义 C# 中大多数运算符的功能。运算符重载需要通过 operator 关键字后跟运算符的形式来定义的&#xff0c;我们可以将被重新定义的运算符看作是具有特殊名称的函数&#xff0c;与其他函数一样&…...

XenCenter 2024 创建一个虚拟机

前言 实现&#xff0c;创建一个虚拟机&#xff0c;内存&#xff0c;cpu&#xff0c;磁盘&#xff0c;名称&#xff0c;网卡&#xff0c;配置 Xen Center 2024 download 创建虚拟机 选择系统类型 定义虚拟机名称 选择ISO镜像库 选择主服务器 分配虚拟机内存&#xff0c;cpu资源…...

tomcat 知多少

Tomcat的缺省端口&#xff1a; 默认端口为8080&#xff0c;可以通过在tomcat安装包conf目录下&#xff0c;service.xml中的Connector元素的port属性来修改端口。 tomcat 常见 Connector 运行模式(优化)&#xff1a; 这三种模式的不同之处如下&#xff1a; BIO &#xff1a; 一…...

【详细讲解语言模型的原理、实战与评估】

&#x1f308;个人主页:程序员不想敲代码啊&#x1f308; &#x1f3c6;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家&#x1f3c6; &#x1f44d;点赞⭐评论⭐收藏 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提…...

Predict the Next “X” ,第四范式发布先知AIOS 5.0

今天&#xff0c;第四范式发布了先知AIOS 5.0&#xff0c;一款全新的行业大模型平台。 大语言模型的原理是根据历史单词去不断预测下一个单词&#xff0c;换一句常见的话&#xff1a;Predict the Next “Word”。 当前对于行业大模型的普遍认知就是沿用这种逻辑&#xff0c;用大…...

PCL使用4PCS配准

一、代码 C++ #include <pcl/registration/ia_fpcs.h> // 4PCS算法 #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pcl/io/pcd_io.h> #include <pcl/io/ply_io.h> #include <boost/thread/thread.hpp> #include…...

【六 (2)机器学习-机器学习建模步骤/kaggle房价回归实战】

一、确定问题和目标&#xff1a; 1、业务需求分析&#xff1a; 与业务团队或相关利益方进行深入沟通&#xff0c;了解他们的需求和期望。 分析业务流程&#xff0c;找出可能的瓶颈、机会或挑战。 思考机器学习如何帮助解决这些问题或实现业务目标。 2、问题定义&#xff1a;…...

vue源码解析——vue如何将template转换为render函数

Vue 将模板&#xff08;template&#xff09;转换为渲染函数&#xff08;render function&#xff09;是 Vue 编译器的核心功能&#xff0c;它是 Vue 实现响应式和虚拟 DOM 的关键步骤。在 Vue 中&#xff0c;模板&#xff08;template&#xff09;是开发者编写的类似 HTML 的代…...

深入理解zookeeper

如果是zookeeper的初学者&#xff0c;可以看&#xff1a; zookeeper快速入门&#xff08;合集&#xff09;-CSDN博客 如果想要深入理解zookeeper&#xff0c;并在面试中取得更好的表现&#xff0c;可以看下面的文章&#xff0c;都是偏面试向的角度写的。 三分钟明白zookeeper…...

【漏洞复现】WordPress Plugin LearnDash LMS 敏感信息暴漏

漏洞描述 WordPress和WordPress plugin都是WordPress基金会的产品。WordPress是一套使用PHP语言开发的博客平台。该平台支持在PHP和MySQL的服务器上架设个人博客网站。WordPress plugin是一个应用插件。 WordPress Plugin LearnDash LMS 4.10.2及之前版本存在安全漏洞&#x…...

phpmyadmin页面getshell

0x00 前言 来到phpmyadmin页面后如何getshell呢&#xff1f;下面介绍两种方法 0x01 select into outfile直接写入 1、利用条件 对web目录需要有写权限能够使用单引号(root) 知道网站绝对路径(phpinfo/php探针/通过报错等) secure_file_priv没有具体值 2、查看secure_file…...

题目:学习static定义静态变量的用法

题目&#xff1a;学习static定义静态变量的用法    There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheate…...

网站推广公司认准乐云seo/厦门seo网站管理

在视图函数中验证表单 因为现在的basic_form视图同时接受两种类型的请求&#xff1a;GET请求和POST请求。所以我们要根据请求方法的不同执行不同的代码。具体来说&#xff0c;首先是实例化表单&#xff0c;如果是GET请求&#xff0c;就渲染模板&#xff1b;如果是POST请求&…...

哪些网站可以做旅游/网络营销计划书怎么写

本文和大家重点讨论一下CSS网页布局中文字排版九大技巧&#xff0c;主要包括如何设定字体、颜色、大小、段落空白&#xff0c;首字下沉、首行缩进。***讲一些常用的web页面中文排版&#xff0c;比如中文字的截断、固定宽度词内折行(word-wrap和word-break)等等。CSS网页布局中文…...

施坦威网站关于我们/seo查询排名系统

建议不要使用Vitamio,各种深坑能够流畅播放720P甚至1080P高清MKV&#xff0c;FLV&#xff0c;MP4&#xff0c;MOV&#xff0c;TS&#xff0c;RMVB等常见格式的视频&#xff0c;支持 MMS, RTSP, RTMP, HLS(m3u8) 等常见的多种视频流媒体协议&#xff0c;包括点播与直播。1.下载V…...

设计素材网站好融资吗/seo关键词优化系统

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2022年高处安装、维护、拆除操作证考试题为高处安装、维护、拆除复习题历年真题&#xff01;2022高处安装、维护、拆除考试练习题及在线模拟考试依据高处安装、维护、拆除考试教材。高处安装、维护、拆除考试题目通过…...

网站开发与程序开发/上优化seo

T-CODE: MASS 批量更改MASS_CHARVAL 特征的批量维护MASS_EINE 信息记录的成批维护MASS_EKKO 采购订单的成批维护MASS_MARC 后勤/配送的成批维护MASS_MEAN 全球贸易项目编号的批量维护MASS_VENDOR 供应商的成批维护MASSD 批量维护MASSOBJ 维护大量维护对象MASSS2V 将系统变式复制…...

网站要去公安局备案吗/湘潭关键词优化公司

mysql数据类型,varchar int char boolean text long double float一.查询&#xff01;查询语句语法&#xff1a;select 列名 from 表名&#xff01;条件查询&#xff1a;关键字 where 开始&#xff0c;后边的就是查询条件&#xff01;having筛选&#xff01;like 模糊查询 like…...