您现在的位置是:群英 > 开发技术 > 编程语言
Golang通道Chan是什么,如何应用
Admin发表于 2022-06-08 17:34:09589 次浏览
相信很多人对“Golang通道Chan是什么,如何应用”都不太了解,下面群英小编为你详细解释一下这个问题,希望对你有一定的帮助

     

下面由golang教程栏目给大家介绍关于Golang 关于通道 Chan 详解,希望对需要的朋友有所帮助!

首先我们来看线程,在golang里面也叫goroutine

在读这篇文章之前,我们需要了解一下并发与并行。golang的线程是一种并发机制,而不是并行。它们之间的区别大家可以上网搜一下,网上有很多的介绍。

下面我们先来看一个例子吧

import(
         "fmt"
)

funcmain(){

    go fmt.Println("1")
    fmt.Println("2")    
}

在golang里面,使用go这个关键字,后面再跟上一个函数就可以创建一个线程。后面的这个函数可以是已经写好的函数,也可以是一个匿名函数

funcmain(){    var i=3    go func(a int) {        fmt.Println(a)
        fmt.Println("1")
    }(i)
    fmt.Println("2")}

上面的代码就创建了一个匿名函数,并且还传入了一个参数i,下面括号里的i是实参,a是形参。

那么上面的代码能按照我们预想的打印1、2、3吗?告诉你们吧,不能,程序只能打印出2。下面我把正确的代码贴出来吧

import(    "fmt"
    "time"    )funcmain(){    var i = 3    go func(a int) {        fmt.Println(a)
        fmt.Println("1")
    }(i)
    fmt.Println("2")
    time.Sleep(1 * time.Second)}

我只是在最后加了一行让主线程休眠一秒的代码,程序就会依

次打印出2、3、1。
那为什么会这样呢?因为程序会优先执行主线程,主线程执行完成后,程序会立即退出,没有多余的时间去执行子线程。如果在程序的最后让主线程休眠1秒钟,那程序就会有足够的时间去执行子线程。

线程先讲到这里,下面我们来看看通道吧。

通道又叫channel,顾名思义,channel的作用就是在多线程之间传递数据的。

创建无缓冲channel

chreadandwrite :=make(chan int)

chonlyread := make(<-chan int) //创建只读channel
chonlywrite := make(chan<- int) //创建只写channel
下面我们来看一个例子:

    ch :=make(chan int)     
    ch <- 1
      go func() {
        <-ch
        fmt.Println("1")
      }()
      fmt.Println("2")

这段代码执行时会出现一个错误:fatal error: all goroutines are asleep - deadlock!

这个错误的意思是说线程陷入了死锁,程序无法继续往下执行。那么造成这种错误的原因是什么呢?

我们创建了一个无缓冲的channel,然后给这个channel赋值了,程序就是在赋值完成后陷入了死锁。因为我们的channel是无缓冲的,即同步的,赋值完成后来不及读取channel,程序就已经阻塞了。这里介绍一个非常重要的概念:channel的机制是先进先出,如果你给channel赋值了,那么必须要读取它的值,不然就会造成阻塞,当然这个只对无缓冲的channel有效。对于有缓冲的channel,发送方会一直阻塞直到数据被拷贝到缓冲区;如果缓冲区已满,则发送方只能在接收方取走数据后才能从阻塞状态恢复。

对于上面的例子有两种解决方案:

1、给channel增加缓冲区,然后在程序的最后让主线程休眠一秒,代码如下:

    ch :=make(chan int,1)
    ch <- 1
    go func() {
        v := <-ch
        fmt.Println(v)
    }()
    time.Sleep(1 * time.Second)
    fmt.Println("2")

这样的话程序就会依次打印出1、2

2、把ch<-1这一行代码放到子线程代码的后面,代码如下:

    ch :=make(chan int)    go func() {
        v := <-ch
        fmt.Println(v)
    }()
    ch <- 1
    fmt.Println("2")

这里就不用让主线程休眠了,因为channel在主线程中被赋值后,主线程就会阻塞,直到channel的值在子线程中被取出。

最后我们看一个生产者和消费者的例子:

import (    "fmt"
    "time")func produce(p chan<- int) {    for i := 0; i < 10; i++ {
        p <- i
        fmt.Println("send:", i)
    }
}func consumer(c <-chan int) {    for i := 0; i < 10; i++ {
        v := <-c
        fmt.Println("receive:", v)
    }
}func main() {
    ch := make(chan int)    go produce(ch)    go consumer(ch)
    time.Sleep(1 * time.Second)
}

在这段代码中,因为channel是没有缓冲的,所以当生产者给channel赋值后,生产者这个线程会阻塞,直到消费者线程将channel中的数据取出。消费者第一次将数据取出后,进行下一次循环时,消费者的线程也会阻塞,因为生产者还没有将数据存入,这时程序会去执行生产者的线程。程序就这样在消费者和生产者两个线程间不断切换,直到循环结束。

下面我们再看一个带缓冲的例子:

import (    "fmt"
    "time")func produce(p chan<- int) {    for i := 0; i < 10; i++ {
        p <- i
        fmt.Println("send:", i)
    }
}func consumer(c <-chan int) {    for i := 0; i < 10; i++ {
        v := <-c
        fmt.Println("receive:", v)
    }
}func main() {
    ch := make(chan int, 10)    go produce(ch)    go consumer(ch)
    time.Sleep(1 * time.Second)
}

在这个程序中,缓冲区可以存储10个int类型的整数,在执行生产者线程的时候,线程就不会阻塞,一次性将10个整数存入channel,在读取的时候,也是一次性读取。


以上就是关于Golang通道Chan是什么,如何应用的介绍啦,需要的朋友可以参考上述内容,希望对大家有帮助,欢迎关注群英网络,小编将为大家输出更多高质量的实用文章!

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

标签: Golang
相关信息推荐
2022-08-01 17:17:24 
摘要:这篇文章主要给大家介绍了关于如何利用Ajax实现地区三级联动的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2022-06-06 17:11:13 
摘要:go语言实现顺序生成数字的方法:首先创建一个go代码示例文件;然后自定义一个makeRange方法;最后通过“for i := range a {a[i] = min + i}”方法顺序生成数字即可。
2022-02-12 17:52:56 
摘要:PHP的双问号代表什么?很多朋友在学习PHP的时候,对在PHP的双问号代码的作用不是很理解,其实双问号是PHP7中的一个NULL合并运算符,其使用类似三元运算表达式,下面我们来了解一下??NULL合并运算符的基本使用。
云活动
推荐内容
热门关键词
热门信息
群英网络助力开启安全的云计算之旅
立即注册,领取新人大礼包
  • 联系我们
  • 24小时售后:4006784567
  • 24小时TEL :0668-2555666
  • 售前咨询TEL:400-678-4567

  • 官方微信

    官方微信
Copyright  ©  QY  Network  Company  Ltd. All  Rights  Reserved. 2003-2019  群英网络  版权所有   茂名市群英网络有限公司
增值电信经营许可证 : B1.B2-20140078   粤ICP备09006778号
免费拨打  400-678-4567
免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
微信公众号
返回顶部
返回顶部 返回顶部