go语言实现多个goroutine之间通信

 更新时间:2026年07月08日 09:33:27   作者:serendipity_hky  
本文主要介绍了go语言实现多个goroutine之间通信,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

channel的定义和使用

channel 用于多个 goroutine 之间的通信

package main

import "fmt"

func main() {
	// 创建一个 channel
	c := make(chan int)

	go func() {
		defer fmt.Println("goroutine结束!")

		fmt.Println("goroutine正在运行")
		// 将数据发送到 channel 中
		c <- 100
	}()

	// 从 channel 中接收数据, 存入到 num
	num := <- c

	fmt.Println("num:", num)
	fmt.Println("main goroutine 结束")
}

为什么 main goroutine 中的执行会在 子goroutine 之后?

(1)main go 已经到达 num := <- c 时,如果 channel 中还没有存在 c,就会对 main go 进行阻塞。
(2)sub go 已经到达 c <- 100,如果 main go 还没有到达 num := <- c,因为此时的管道 c 是无缓冲的,就会对 sub go 进行阻塞。

channel——有缓冲和无缓冲同步

1. 无缓冲的channel

(1)在第1步,两个goroutine都到达通道,但哪个都没有开始执行发送或者接收。
(2)在第2步,左侧的goroutine将它的手伸进了通道,这模拟了向通道发送数据的行为。这时,这个goroutine会在通道中被锁住,直到交换完成。
(3)在第3步,右侧的goroutine将它的手放入通道,这模拟了从通道里接收数据。这个goroutine一样也会在通道中被锁住,直到交换完成。
(4)在第4步和第5步,进行交换,并最终,在第6步,两个goroutine都将它们的手从通道里拿出来,这模拟了被锁住的goroutine得到释放。两个goroutine现在都可以去做其他事情了。

2. 有缓冲的channel

package main

import (
	"fmt"
	"time"
)

func main() {
	// 创建一个容量为3的 channel(有缓冲的channel)
	c := make(chan int, 3)

	go func() {
		defer fmt.Println("子go程结束!")

		for i := 0; i < 3; i++ {
			c <- i
			fmt.Println("子go程 i = ", i, "  元素个数:", len(c), "  元素个数:", cap(c))
		}	
	}()

	time.Sleep(1 * time.Second)

	for i := 0; i < 3; i++ {
		// 从 channel 中获取数据
		num := <- c
		fmt.Println("num =", num)
	}

	fmt.Println("main goroutine 运行结束")

}

(1)在第1步,右侧的goroutine正在从通道接收一个值。
(2)在第2步,右侧的这个goroutine独立完成了接收值的动作,而左侧的goroutine正在发送一个新值到通道里。
(3)在第3步,左侧的goroutine还在向通道发送新值,而右侧的goroutine正在从通道接收另外一个值。这个步骤里的两个操作既不是同步的,也不会互相阻塞。
(4)最后,在第4步,所有的发送和接收都完成,而通道里还有几个值,也有一些空间可以存更多的值。

channel——关闭channel

package main

import "fmt"

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

	go func() {
		for i := 0; i < 3; i++ {
			c <- i
		}

		// close 关闭 channel
		close(c)
	}()

	for {
		// ok 为 true 表示 channel 没有关闭, ok 为 false 表示 channel 已经关闭
		if data, ok := <- c; ok {
			fmt.Println("data: ", data) 
		} else {
			break
		}
	}

	fmt.Println("main goroutine 结束")

}

(1)channel不像文件一样需要经常去关闭,只有当你确实没有任何发送数据了,或者想显式的结束range循环之类的,才去关闭channel;
(2)关闭channel后,无法向channel再发送数据(引发panic错误后导致接收立即返回零值);
(3)关闭channel后,可以继续从channel接收数据;
(4)对于nil channel,无论收发都会被阻塞。

channel 与 range

package main

import "fmt"

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

	go func() {
		for i := 0; i < 3; i++ {
			c <- i
		}

		// close 关闭 channel
		close(c)
	}()

	/* for {
		// ok 为 true 表示 channel 没有关闭, ok 为 false 表示 channel 已经关闭
		if data, ok := <- c; ok {
			fmt.Println("data: ", data) 
		} else {
			break
		}
	} */

	// 可以使用 range 代替不断迭代的操作的cahnnel
	for data := range c {
		fmt.Println("data: ", data)
	}

	fmt.Println("main goroutine 结束")

}

channel 与 select

单流程下,一个go只能监控一个 channel 状态,select 可以完成监控多个 channel 的状态。

package main

import (
	"fmt"
)

func method(c, quit chan int) {
	x, y := 1, 1

	for {
		select {
		case c <- x:
			// 如果 c 可写入,执行下面
			x = y
			y = x + y
		case <- quit:
			fmt.Println("quit.....")
			return 
		}
	}
}

func main() {
	c := make(chan int)
	quit := make(chan int)

	go func() {
		for i := 0; i < 6; i++ {
			fmt.Println(<-c)
		}

		quit <- 0
	}()

	method(c, quit)
}

到此这篇关于go语言实现多个goroutine之间通信的文章就介绍到这了,更多相关go语言 多goroutine通信内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用Go语言开发短链接服务的方法

    使用Go语言开发短链接服务的方法

    短链接一般是通过映射关系,将长长的一串网址,映射到几个字符的短链接上,建立好这种映射关系之后保存到数据库里,用户每次访问短链接的时候,这篇文章主要介绍了使用Go语言开发一个短链接服务,需要的朋友可以参考下
    2024-03-03
  • 详解Golang中字符串的使用

    详解Golang中字符串的使用

    这篇文章主要为大家详细介绍了Golang中字符串的使用,文中的示例代码讲解详细,对我们学习Golang有一定的帮助,感兴趣的小伙伴可以了解一下
    2022-10-10
  • Golang 并发以及通道的使用方式

    Golang 并发以及通道的使用方式

    这篇文章主要介绍了Golang 并发以及通道的使用方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • Go错误处理之errors包全面解析与最佳实践

    Go错误处理之errors包全面解析与最佳实践

    标准库errors包是Go提供的基础错误处理工具,它不仅允许我们创建和包装错误,还支持丰富的功能,下面小编将从基础到高级,带你深入掌握 errors 包的使用,快跟随小编一起学习起来吧
    2026-03-03
  • 一文教你如何快速学会Go的切片和数组数据类型

    一文教你如何快速学会Go的切片和数组数据类型

    数组是属于同一类型的元素的集合。切片是数组顶部的方便、灵活且功能强大的包装器。本文就来和大家聊聊Go中切片和数组的使用,需要的可以参考一下
    2023-03-03
  • Golang初始化MySQL数据库方法浅析

    Golang初始化MySQL数据库方法浅析

    这篇文章主要介绍了Golang初始化MySQL数据库的方法,数据库的建立第一步即要初始化,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-05-05
  • 浅谈Go 语言中逃逸分析是怎么进行的

    浅谈Go 语言中逃逸分析是怎么进行的

    Go 语言的逃逸分析是在编译阶段进行的静态分析过程,用于确定变量的内存分配位置,本文就来介绍一下逃逸分析是怎么进行的,具有一定的参考价值,感兴趣的可以了解一下
    2025-10-10
  • golang使用tail实现追踪文件变更

    golang使用tail实现追踪文件变更

    这篇文章主要为大家介绍了golang如何借助 github.com/hpcloud/tail ,实现实时追踪文件变更,达到类似shell命令tail -f的效果,感兴趣的小伙伴可以了解一下
    2023-08-08
  • Golang测试框架goconvey进行单元测试流程介绍

    Golang测试框架goconvey进行单元测试流程介绍

    goconvey是一款针对Golang的测试框架,可以管理和运行测试用例,同时提供了丰富的断言函数,并支持很多Web界面特性,这篇文章主要介绍了使用goconvey进行单元测试流程,感兴趣的同学可以参考下文
    2023-05-05
  • 深入学习Golang并发编程必备利器之sync.Cond类型

    深入学习Golang并发编程必备利器之sync.Cond类型

    Go 语言的 sync 包提供了一系列同步原语,其中 sync.Cond 就是其中之一。本文将深入探讨 sync.Cond 的实现原理和使用方法,帮助大家更好地理解和应用 sync.Cond,需要的可以参考一下
    2023-05-05

最新评论