GOLANG进阶 之 接口(interface) 与 管道(channel)

news/2025/3/19 21:36:19/

        好久没有跟新过文章了,小编最近有点忙,写文章的频率下降了许多,但是还是会持续跟新的,希望关注的同学仔细学习。

        首先讲一下接口具体是个啥?小白可以结合官方定义和小编自己的理解共同学习下

        官方解释:接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节。

        自己理解:面向过程的开发 变成  面向对象编程;相当于生成了一个类,需要这个类的功能直接调用就好,不用再重新定义

       

怎么做?简单来说就是:接口调用(结构体作为函数入参):第二步和第三步可以合并


第一步:结构体
type User struct {
         属性名  值

        ..................................
}

第二步:定义方法
func (z *User ) Pay(amount int64) {
  fmt.Printf("测试保留两位小数:%.2f。\n", float64(amount/100))
}

第三步:定义方法
func Checkout(obj *User ) {
    obj.Pay(100)
}

第四步:主方法调用
func main() {
    Checkout(&User {})
}

输出值:测试保留两位小数:100.00

最基础的就是这样的,其余的以后会结合项目讲解,先打好基础,后面学习才会更轻松

        管道(channel)又是个啥?等小编一一解释(这里有必要学习一下调度机制GPM,这个后面小编会单独讲解)

        官方解释:可以看作是一个通信的桥梁,用于连接不同操作的 goroutine。当多个 goroutine 同时访问同一资源时,我们就需要使用管道来协调它们的访问,锁具有一定的局限性,因为当我们使用锁时,它只允许一个 goroutine 访问资源,而通常情况下我们需要更高效的方法协调 goroutine 的并发操作,这时就需要用到管道。并且管道是一种并发安全的数据结构

        自己理解:一个goroutine的队列,保证goroutine的有序执行

        了解知识:并发模型

            线程&锁模型
            Actor模型
            CSP模型
            Fork&Join模型

下面以代码的形式来理解下:

代码片段1:

func hello() {
    fmt.Println("hello")
}

func main() {
    hello()
    fmt.Println("你好")
}

输出:
hello
你好

代码片段2:

func hello() {
    fmt.Println("hello")
}

func main() {
    go hello() // 启动另外一个goroutine去执行hello函数
    fmt.Println("你好")
}

输出:
你好

为什么会出现这样的情况?

        go关键字:启动一个 goroutine 去执行 hello 这个函数,这样可以模拟并发

为什么只执行了最后的输出?
        其实在 Go 程序启动时,Go 程序就会为 main 函数创建一个默认的 goroutine

        在上面的代码中我们在 main 函数中使用 go 关键字创建了另外一个 goroutine 去执行 hello 函数,而此时 main goroutine 还在继续往下执行,我们的程序中此时存在两个并发执行的 goroutine。
        当 main 函数结束时整个程序也就结束了,同时 main goroutine 也结束了,所有由 main goroutine 创建的 goroutine 也会一同退出。也就是说我们的 main 函数退出太快,另外一个 goroutine 中的函数还未执行完程序就退出了,导致未打印出“hello”。

图形解释:(解释代码片段1)

所以要有输出两个值的效果就需要sync 包中的WaitGroup的功能

var wg sync.WaitGroup

func hello() {
    fmt.Println("hello")
    wg.Done() // 当前goroutine完成
}

func main() {
    wg.Add(1) // 登记1个goroutine
    go hello()
    fmt.Println("你好")
    wg.Wait() // 阻塞等待的goroutine完成
}

输出:
    hello
    你好

图形解释:

        虽然可以使用共享内存进行数据交换,但是共享内存在不同的 goroutine 中容易发生竞态问题,为了保证数据交换的正确性,很多并发模型中必须使用互斥量对内存进行加锁,这种做法势必造成性能问题

        Go语言采用的并发模型是CSP(Communicating Sequential Processes),提倡通过通信共享内存而不是通过共享内存而实现通信。

        重点:如果说 goroutine 是Go程序并发的执行体,channel就是它们之间的连接。channel是可以让一个 goroutine 发送特定值到另一个 goroutine 的通信机制。通道像一个传送带或者队列,总是遵循先入先出(First In First Out)的规则,保证收发数据的顺序。每一个通道都是一个具体类型的导管,也就是声明channel的时候需要为其指定元素类型。

初始化管道:       

var ch1 chan int   // 声明一个传递整型的通道
var ch2 chan bool  // 声明一个传递布尔型的通道
var ch3 chan []int // 声明一个传递int切片的通道
ch4 := make(chan int)
ch5 := make(chan bool, 1)  // 声明一个缓冲区大小为1的通道

管道的使用:将一个值发送到通道中
ch1 <- 10 

管道的使用:从一个通道中接收值
x := <- ch1

管道的使用:关闭管道
close(ch1 )
基础使用方法已经讲解完成,后面延伸讲一下:
    


无缓冲管道:

func main() {
    ch := make(chan int)
    ch <- 10
    fmt.Println("发送成功")
}
报错信息:

fatal error: all goroutines are asleep - deadlock! //所有goroutine都处于休眠状态-死锁!
goroutine 1 [chan send]:

        首先无缓冲通道ch上的发送操作会阻塞,直到另一个 goroutine 在该通道上执行接收操作,这时数字10才能发送成功,两个 goroutine 将继续执行。
        相反,如果接收操作先执行,接收方所在的 goroutine 将阻塞,直到 main goroutine 中向该通道发送数字10。
        使用无缓冲通道进行通信将导致发送和接收的 goroutine 同步化。因此,无缓冲通道也被称为同步通道
    

解决办法1:为什么这个就可以?

        首先无缓冲通道ch上的发送操作会阻塞,直到另一个 goroutine 在该通道上执行接收操作,这时数字10才能发送成功,两个 goroutine 将继续执行。

        相反,如果接收操作先执行,接收方所在的 goroutine 将阻塞直到 main goroutine 中向该通道发送数字10
        使用无缓冲通道进行通信将导致发送和接收的 goroutine 同步化。因此,无缓冲通道也被称为
同步通道


func recv(c chan int) {
    ret := <-c
    fmt.Println("接收成功", ret)
}

func main() {
    ch := make(chan int)
    go recv(ch) 
    ch <- 10
    fmt.Println("发送成功")
}
    
    
解决办法2:缓冲管道

func main() {
    ch := make(chan int, 1) // 创建一个容量为1的有缓冲区通道
    ch <- 10
    fmt.Println("发送成功")
}
    

现阶段理解到这个程度就可以了,后续深入的小编再讲,结合项目实战讲


http://www.ppmy.cn/news/1021543.html

相关文章

uniapp开发小程序-分包(微信错误码:800051)

在使用uniapp开发小程序时&#xff0c;上传的时候因为文件过大&#xff0c;显示上传失败。 以下是开发过程中遇到的问题及解决方法&#xff1a; 1. 问题一&#xff1a;因为文件过大&#xff0c;显示上传失败 ①尝试过把本地使用的图片压缩到最小&#xff1b; ②把图片转换为网…

内网隧道—HTTP\DNS\ICMP

本文仅限于安全研究和学习&#xff0c;用户承担因使用此工具而导致的所有法律和相关责任&#xff01; 作者不承担任何法律和相关责任&#xff01; HTTP隧道 Neo-reGeorg Neo-reGeorg 是一个旨在积极重构 reGeorg 的项目&#xff0c;目的是&#xff1a; 提高可用性&#xff0…

什么是IMAP协议?

IMAP&#xff08;Internet Message Access Protocol&#xff09;是一个应用层协议&#xff0c;用于访问和管理存储在远程服务器上的电子邮件。相比于POP3&#xff0c;IMAP提供了更加丰富的功能&#xff0c;特别适用于需要在多台设备上访问电子邮件的用户。以下是关于IMAP的详细…

FreeRTOS源码分析-11 软件定时器

目录 1 软件定时器概念及其应用 1.1 软件定时器定义 1.2 FreeRTOS软件定时器介绍 1.3 FreeRTOS软件定时器工作原理 2 软件定时器函数应用 2.1 功能需求 2.2 API 2.3 功能实现 3 软件定时器原理源码分析 3.1 软件定时器控制块 3.2 软件定时器任务&软件定时器创建 …

Lecoode有序数组的平方977

题目建议&#xff1a; 本题关键在于理解双指针思想 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 文章讲解&#xff1a;代码随想录 视频讲解&#xff1a; 双指针法经典题目 | LeetCode&#xff1a;977.有序数组的平方_哔哩…

在用的二手电动汽车,雨季时,要注意保养哪些地方?

二手电动汽车在雨季的保养有一些特别需要注意的地方。首先&#xff0c;你要确保你的车子有足够的防水措施。电动汽车的电池组和控制系统通常都装在车辆底部&#xff0c;而这些部分是最怕水的。如果这些部分进水&#xff0c;可能会导致严重的电气故障&#xff0c;甚至可能会引起…

二次封装ajax和axios

ajax app.config.globalProperties.$http function(url, method, data, async, fun) {$.ajax({url: baseUrl url, //请求地址type: method, //请求方式dataType: json, //数据类型contentType: "application/json",xhrFields: { //跨域设置withCredentials: t…

网络安全—黑客技术【自学】

一、黑客是什么 原是指热心于计算机技术&#xff0c;水平高超的电脑专家&#xff0c;尤其是程序设计人员。但后来&#xff0c;黑客一词已被用于泛指那些专门利用电脑网络搞破坏或者恶作剧的家伙。 二、学习黑客技术的原因 其实&#xff0c;网络信息空间安全已经成为海陆空之…