当前位置: 代码网 > it编程>前端脚本>Golang > Go无缓冲通道(同步通道)的实现

Go无缓冲通道(同步通道)的实现

2025年02月13日 Golang 我要评论
无缓冲的通道又称为阻塞的通道,我们来看一下如下代码片段。package mainimport "fmt"func main() { ch := make(chan int) ch <

无缓冲的通道又称为阻塞的通道,我们来看一下如下代码片段。

package main

import "fmt"

func main() {
    ch := make(chan int)
    ch <- 1
    fmt.println("发送成功")
}

上面这段代码能够通过编译,但是执行的时候会出现以下错误:

在这里插入图片描述

deadlock表示我们程序中的 goroutine 都被挂起导致程序死锁了。为什么会出现deadlock错误呢?

因为我们使用ch := make(chan int)创建的是无缓冲的通道,无缓冲的通道只有在有接收方能够接收值的时候才能发送成功,否则会一直处于等待发送的阶段

上面的代码会阻塞在ch <- 1这一行代码形成死锁,那如何解决这个问题呢?

其中一种可行的方法是创建一个 goroutine 去接收值,例如:

package main

import (
    "sync"
)

func main() {
    var wg sync.waitgroup
    wg.add(1)
    ch := make(chan int)
    ch <- 1
    go func() {
       defer wg.done()
        v := <-ch
       fmt.println(v)
    }()
    close(ch)
    wg.wait()
}

在这里插入图片描述

我们已经开了一个go协程从管道中读去数据了,为什么还会报错呢?

因为当程序执行到 ch <- 1时,进已经发生了阻塞,下面的go协程还没有来得及启动。
go的channel在执行写入时会先检查在此之前有没有读取数据的一方已经存在,在读取时会先检查在此之前有没有写入方已经存在。

当我们将读的协程先启动,再写入,就可以了,代码如下:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.waitgroup
    wg.add(1)
    ch := make(chan int)
    go func() {
       defer wg.done()
       v := <-ch
       fmt.println(v)
    }()
    ch <- 1
    close(ch)
    wg.wait()
}

在这里插入图片描述

同理,如果对一个无缓冲通道执行接收操作时,没有任何向通道中发送值的操作那么也会导致接收操作阻塞

package main

import "fmt"

func main() {
    ch := make(chan int)
    <-ch
    fmt.println("接收成功")
}

在这里插入图片描述

其中一种可行的方法是创建一个 goroutine 去写入值,例如:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.waitgroup
    wg.add(1)
    ch := make(chan int)
    v := <-ch
    go func() {
       defer wg.done()
       ch <- 1
    }()
    fmt.println(v)
    close(ch)
    wg.wait()
}

在这里插入图片描述

同理,因为当程序执行到 v := <-ch 时,进已经发生了阻塞,下面的go协程还没有来得及启动。
当我们将写的协程先启动,再读取,就可以了,代码如下:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.waitgroup
    wg.add(1)
    ch := make(chan int)
    go func() {
       defer wg.done()
       ch <- 1
    }()
    v := <-ch
    fmt.println(v)
    close(ch)
    wg.wait()
}

在这里插入图片描述

使用无缓冲通道进行通信将导致发送和接收的 goroutine 同步化。因此,无缓冲通道也被称为同步通道
同步:两个goroutine1(写入方)、goroutine2(读取方),
goroutine1先执行,如果想要再次发送(写入)数据的话,必须等待goroutine2将channel中的数据取出来(读取)之后,才能再次发送。
goroutine2先执行,如果想要再次接收数据的话,必须等待goroutine1再次向channel中写入数据之后,才能再次接收。
执行顺序(goroutine1,goroutine2,goroutine1,goroutine2…)goroutine1和goroutine2交替执行。
示例演示:使用一个无缓冲channel和两个goroutine实现交替打印一个字符串。

package main

import "fmt"

func main() {
    ch := make(chan int)

    str := "hello, world"

    go func() {
       for {
          index, ok := <-ch
          if !ok {
             break
          }
          if index >= len(str) {
             close(ch)
             break
          }
          fmt.printf("goroutine1 : %c\n", str[index])
          ch <- index + 1
       }
    }()

    ch <- 0

    for {
       index, ok := <-ch
       if !ok {
          break
       }
       if index >= len(str) {
          close(ch)
          break
       }
       fmt.printf("goroutine1 : %c\n", str[index])
       ch <- index + 1
    }

}

在这里插入图片描述

到此这篇关于go无缓冲通道(同步通道)的实现的文章就介绍到这了,更多相关go无缓冲通道内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网! 

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com