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

 更新时间:2025年02月06日 09:53:07   作者:2301_76723322  
本文主要介绍了Go无缓冲通道(同步通道)的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

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

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无缓冲通道内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • golang原生http包实现各种情况的get请求方式

    golang原生http包实现各种情况的get请求方式

    这篇文章主要介绍了golang原生http包实现各种情况的get请求方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Go中unsafe.Pointer类型的使用小结

    Go中unsafe.Pointer类型的使用小结

    unsafe.Pointer 是 Go 语言标准库 unsafe 包中的一个特殊类型,用于在不同类型的指针之间进行 无类型转换,允许你绕过 Go 的类型系统进行底层操作,感兴趣的可以了解一下
    2026-02-02
  • Go语言变量与基础数据类型详情

    Go语言变量与基础数据类型详情

    Go 是静态(编译型)语言,是区别于解释型语言的弱类型语言(静态:类型固定,强类型:不同类型不允许直接运算),下面文章将对其进行详细介绍,需要的朋友可以参考一下
    2021-09-09
  • 如何使用go-zero开发线上项目

    如何使用go-zero开发线上项目

    这篇文章主要介绍了如何使用go-zero开发线上项目,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • Go语言中的多种测试方法

    Go语言中的多种测试方法

    本文主要介绍了Go语言中的多种测试方法,包括单元测试、表格驱动测试、基准测试等,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2025-07-07
  • Golang设计模式之责任链模式讲解和代码示例

    Golang设计模式之责任链模式讲解和代码示例

    责任链是一种行为设计模式, 允许你将请求沿着处理者链进行发送, 直至其中一个处理者对其进行处理,本文就详细给大家介绍一下Golang 责任链模式,文中有详细的代码示例,需要的朋友可以参考下
    2023-06-06
  • 使用go xorm来操作mysql的方法实例

    使用go xorm来操作mysql的方法实例

    今天小编就为大家分享一篇关于使用go xorm来操作mysql的方法实例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • 一文带你揭秘Go中new()和make()函数的区别和用途

    一文带你揭秘Go中new()和make()函数的区别和用途

    Go(或 Golang)是一种现代、静态类型、编译型的编程语言,专为构建可扩展、并发和高效的软件而设计,它提供了各种内置的函数和特性,帮助开发人员编写简洁高效的代码,在本博客文章中,我们将探讨 new() 和 make() 函数之间的区别,了解何时以及如何有效地使用它们
    2023-10-10
  • Go语言中的goroutine和channel如何协同工作

    Go语言中的goroutine和channel如何协同工作

    在Go语言中,goroutine和channel是并发编程的两个核心概念,它们协同工作以实现高效、安全的并发执行,本文将详细探讨goroutine和channel如何协同工作,以及它们在并发编程中的作用和优势,需要的朋友可以参考下
    2024-04-04
  • golang压缩与解压缩文件的示例代码

    golang压缩与解压缩文件的示例代码

    这篇文章主要给大家介绍了golang压缩与解压缩文件,文中通过代码示例给大家介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-02-02

最新评论