搜索
首页后端开发Golang一篇文章带你了解Go语言基础之并发(channel)

为什么需要channel

channel在Go中,也叫做管道,是用来多线程之间共享数据的。

通常情况下,在Go中的共享数据用的也是channel,但是在Go有两种共享数据方式。

  • 共享内存实现通讯。

  • 通过管道(channel)通讯(推荐)。

为啥子共享内存通讯不太推荐?

示例代码:多线程修改一个值。

函数

func Calc() {
    defer wg.Done()
    NUM = NUM - 1
}

main

var NUM = 100
var wg sync.WaitGroup


func main() {
    for i := 0; i<100;i++  {
        wg.Add(1)
        go Calc()
}
    wg.Wait()
    fmt.Println(NUM)
}

执行结果

一篇文章带你了解Go语言基础之并发(channel)

没错,是2,懵了吧,哈哈哈,理论应该是0才对呀。

这是为啥?

这就是共享内存不太推荐的原因,我们的代码已经是多线程了。

第一个函数代码中,第3行,NUM = NUM - 1

如果多个线程同时执行到这一行,并且没有加锁,就会出现数据错乱。

那该怎么做呢?

加锁,加锁可以保证某一段代码只能被一个线程执行,防止被争抢。

代码

func Calc() {
    defer wg.Done()
    mutex.Lock()
    NUM = NUM - 1
    mutex.Unlock()
}

第3行加锁,第5行解锁

执行结果

一篇文章带你了解Go语言基础之并发(channel)

这次真的是0的,不管执行几次。

但是会发现一个问题,如果采用这种方式,需要常常注意竞争问题。

所以不是太推荐,需要考虑的比较多,并且各种加锁会消耗性能。

channel语法

channel格式

var 变量名 chan 类型
例如
var x1 chan int //x1管道里面只能存int类型数据
var x2 chan string //x2管道里面只能存字符串类型数据

注意

一篇文章带你了解Go语言基础之并发(channel)

定义管道时,chan int是一个整体,别搞错了各位。

创建channel

创建channel,只能通过make创建。

格式

var 变量名 = make(chan 类型,[管道大小])
示例
var chan1 = make(chan int,10)//管道可以放10个int元素
var chan2 = make(chan string,5)//管道可以放5个string元素

channel操作

创建一个管道。

ch = make(chan int,10)

channel是一个管道,就像一个管子。

所以可以像管子里面塞东西,并且能取东西关闭管道就是这个管道不能用了,里面的值取完就打样了

像管子塞东西(发送)ch

从管子取东西(接收)var x =

关闭管子close(ch)

注意:channel是先入先出结构,就像这样。

一篇文章带你了解Go语言基础之并发(channel)

注意事项:

  • 如果通道塞满了,再塞 会阻塞住。

  • 如果通道关闭了,是不能再塞值了,否则会panic。

  • 即使通道关闭了,依然可以取值,直到将管道的值取完,取完后得到的是对应类型零值。

  • 管道不能重复关闭,重复关闭会panic。


无缓冲管道

无缓冲就是这个管道没有长度,就像这样。

就像快读员没有快递柜,需要直接将快递给客户,如果没人要就撂摊子。

一篇文章带你了解Go语言基础之并发(channel)

示例代码

package main


import (
    "fmt"
)


//模拟张三
func 张三(x chan string) {
    var a = <-x
    fmt.Println(a)
}


func main() {
    //通道没有长度,就是无缓冲通道
    var x = make(chan string)
    go 张三(x)
    x <- "张三的快递"
    fmt.Println("张三快递交付成功")
}

第16行写入一个值,同理,张三就要等着去接,如果没人接,那就完了。

假设注释第9行代码。

一篇文章带你了解Go语言基础之并发(channel)

直接报错,all goroutines are asleep - deadlock!,这句话的意思是所有的协程都睡着了,死锁

无缓冲说明通道长度为0发送一个值会阻塞住

这就相当于快递员直接找张三,但是张三没了,但是快递员还得一直等着,等等等,然后挂了,终究还是没送出去。

有缓冲管道

一篇文章带你了解Go语言基础之并发(channel)

这个就简单啦,多了一个快递柜,快递员直接将快递仍快递柜就行了。

示例代码

package main


import (
    "fmt"
    "sync"
)


var wg sync.WaitGroup


//快递员,快递员放10个快递
func 快递员(kuaidigui chan string) {
    defer wg.Done()
    for i := 0; i < 10; i++ {
        fmt.Println("快递员放入了第",i,"快递")
        kuaidigui <- fmt.Sprintf("第%d个快递", i)
}
    //放完快递就关闭了通道
    close(kuaidigui)
}


//张三,拿走3个快递
func 张三(kuaidigui chan string) {
    defer wg.Done()
    for i := 0; i < 3; i++ {
        fmt.Println("张三拿走" + <-kuaidigui)
}
}
//李四拿走7个快递
func 李四(kuaidigui chan string) {
    defer wg.Done()
    for i := 0; i < 7; i++ {
        fmt.Println("李四拿走" + <-kuaidigui)
}
}
func main() {
    //快递柜,10个大小
    var 快递柜 = make(chan string, 10)
    wg.Add(3)
    go 快递员(快递柜)
    go 张三(快递柜)
    go 李四(快递柜)
    wg.Wait()
}

执行结果

一篇文章带你了解Go语言基础之并发(channel)

遍历channel两种方式

代码

func main() {
    //快递柜,10个大小
    var ch = make(chan int, 10)
    //向管道中发送值
    for i := 0; i < 10; i++ {
        ch <- i
}
    //方式一取值
    //for {
    //i, ok := <-ch
    ////取完值ok就是false
    //if !ok {
    //      //结束循环
    //      break
    //}
    //fmt.Println(i)
    //}
    //方式二取值
    for i:=range ch{
        fmt.Println(i)
}
}

执行结果

一篇文章带你了解Go语言基础之并发(channel)

报错是因为我在main中完成了发送值和取值两个操作,所以会出现上述问题,但是结果是没有错的。

单向通道

我们知道通道是可以发送值取值的,但是某些场景为了安全起见,理论来说只能取值,后者只能发送值。

单向通道通常只在函数参数中体现。

  • 形参 chan只写。

  • 形参 只读。

修改上述快递员代码。

package main


import (
    "fmt"
    "sync"
)


var wg sync.WaitGroup


//快递员,快递员放10个快递,只写 chan<- string
func 快递员(kuaidigui chan<- string) {
    defer wg.Done()
    for i := 0; i < 10; i++ {
        fmt.Println("快递员放入了第", i, "快递")
        kuaidigui <- fmt.Sprintf("第%d个快递", i)
}
    //放完快递就关闭了通道
    close(kuaidigui)
}


//张三,拿走3个快递,只读<-chan string
func 张三(kuaidigui <-chan string) {
    defer wg.Done()
    for i := 0; i < 3; i++ {
        fmt.Println("张三拿走" + <-kuaidigui)
}
}


//李四拿走7个快递
func 李四(kuaidigui <-chan string) {
    defer wg.Done()
    for i := 0; i < 7; i++ {
        fmt.Println("李四拿走" + <-kuaidigui)
}
}
func main() {
    //快递柜,10个大小
    var 快递柜 = make(chan string, 10)
    wg.Add(3)
    go 快递员(快递柜)
    go 张三(快递柜)
    go 李四(快递柜)
    wg.Wait()
}

总结

上述讲述了Go语言并发如何和channel配合使用,毕竟我们一般的任务都不是单独运行的,都是互相配合的。

我们讲述了如何创建channel如何使用channel有缓冲管道和无缓冲管道区别,并且拒了一个快递员例子来展示协程和channel如何配合,最后用单向通道又加固了一下代码。

我的代码中使用了中文命名变量名是为了好看,实际开发中千万不要这样!!!

以上是一篇文章带你了解Go语言基础之并发(channel)的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:Go语言进阶学习。如有侵权,请联系admin@php.cn删除
Golang vs. Python:利弊Golang vs. Python:利弊Apr 21, 2025 am 12:17 AM

Golangisidealforbuildingscalablesystemsduetoitsefficiencyandconcurrency,whilePythonexcelsinquickscriptinganddataanalysisduetoitssimplicityandvastecosystem.Golang'sdesignencouragesclean,readablecodeanditsgoroutinesenableefficientconcurrentoperations,t

Golang和C:并发与原始速度Golang和C:并发与原始速度Apr 21, 2025 am 12:16 AM

Golang在并发性上优于C ,而C 在原始速度上优于Golang。1)Golang通过goroutine和channel实现高效并发,适合处理大量并发任务。2)C 通过编译器优化和标准库,提供接近硬件的高性能,适合需要极致优化的应用。

为什么要使用Golang?解释的好处和优势为什么要使用Golang?解释的好处和优势Apr 21, 2025 am 12:15 AM

选择Golang的原因包括:1)高并发性能,2)静态类型系统,3)垃圾回收机制,4)丰富的标准库和生态系统,这些特性使其成为开发高效、可靠软件的理想选择。

Golang vs.C:性能和速度比较Golang vs.C:性能和速度比较Apr 21, 2025 am 12:13 AM

Golang适合快速开发和并发场景,C 适用于需要极致性能和低级控制的场景。1)Golang通过垃圾回收和并发机制提升性能,适合高并发Web服务开发。2)C 通过手动内存管理和编译器优化达到极致性能,适用于嵌入式系统开发。

golang比C快吗?探索极限golang比C快吗?探索极限Apr 20, 2025 am 12:19 AM

Golang在编译时间和并发处理上表现更好,而C 在运行速度和内存管理上更具优势。1.Golang编译速度快,适合快速开发。2.C 运行速度快,适合性能关键应用。3.Golang并发处理简单高效,适用于并发编程。4.C 手动内存管理提供更高性能,但增加开发复杂度。

Golang:从Web服务到系统编程Golang:从Web服务到系统编程Apr 20, 2025 am 12:18 AM

Golang在Web服务和系统编程中的应用主要体现在其简洁、高效和并发性上。1)在Web服务中,Golang通过强大的HTTP库和并发处理能力,支持创建高性能的Web应用和API。2)在系统编程中,Golang利用接近硬件的特性和对C语言的兼容性,适用于操作系统开发和嵌入式系统。

Golang vs.C:基准和现实世界的表演Golang vs.C:基准和现实世界的表演Apr 20, 2025 am 12:18 AM

Golang和C 在性能对比中各有优劣:1.Golang适合高并发和快速开发,但垃圾回收可能影响性能;2.C 提供更高性能和硬件控制,但开发复杂度高。选择时需综合考虑项目需求和团队技能。

Golang vs. Python:比较分析Golang vs. Python:比较分析Apr 20, 2025 am 12:17 AM

Golang适合高性能和并发编程场景,Python适合快速开发和数据处理。 1.Golang强调简洁和高效,适用于后端服务和微服务。 2.Python以简洁语法和丰富库着称,适用于数据科学和机器学习。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

功能强大的PHP集成开发环境

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),