Go 语言学习之 goroutine 和 channel

简介: Go 语言学习之 goroutine 和 channel

01

goroutine


当一个 go 程序运行时,调用 main 函数入口的 goroutine 是主 goroutine,我们还可以使用关键字 go 创建新的 goroutine。在 Go 语言中,创建 goroutine 的语法很简单,只需要在函数或方法调用前加上 go 关键字。


02

channel


channel 是可以让一个 goroutine 发送特定的值到另一个 goroutine 的通信机制。Go 官方鼓励使用 CSP 并发编程风格,以通信代替内存共享,实现并发安全。


与 map 类似,channel 也是使用内置函数 make 创建。channel 是引用类型,它的零值是 nil,channel 可以和 nil 进行比较,相同类型的 channel 可以使用 “==” 符号进行比较。


使用内置函数 make 创建 channel 时,有两个参数,第一个参数是元素类型,第二个可选参数是 channel 的容量。不设置 channel 容量称为无缓冲 channel,设置 channel 容量称为缓冲 channel。无缓冲 channel 是一种阻塞的同步 channel。内置函数 cap 可以获取缓冲 channel 的容量,内置函数 len 可以获取缓冲 channel 的元素个数。


03

channel 操作


channel 操作有三种,分别是 send、receive 和 close。send 操作可以从一个执行的 goroutine 传输一个值到另一个执行 receive 操作的 goroutine。


send 操作和 receive 操作都使用 “<-” 操作符,在 send 语句中,channel 和值分别在操作符左右两边,在 receive 语句中,操作符放在 channel 操作数的前面。


close 操作通过设置一个标志位来表示当前值已经 send 完毕,channel 不会再被 send 值了,close 操作后的 send 操作将导致宕机。在一个已经执行 close 操作的 channel 上执行 receive 操作,将获取这个 channel 上所有已经 send 的值,直到 channel 为空。


缓冲 channel 的 send 操作在队列的尾部插入一个元素,receive 操作在队列的头部移除一个元素。如果缓冲 channel 容量占满,send 操作会阻塞所在的 goroutine,直到另一个 goroutine 对它执行 receive 操作来腾出可用空间。如果缓冲 channel 是空的,receive 操作的 goroutine 阻塞,直到另一个 goroutine 在这个缓冲 channel 上 send 数据。


需要注意的是,如果在同一个缓冲 channel 上执行 send 操作和 receive 操作,是将缓冲 channel 错误地作为队列使用了。在实际项目开发中,send 操作和 receive 操作是由不同的 goroutine 执行的。


无缓冲 channel 的每一次 send 操作都对应一次 receive 操作,实现强同步。缓冲 channel 的 send 操作和 receive 操作是解耦的。我们如果事先可以知道需要 send 的值的数量上限,可以创建一个容量是使用上限的缓冲 channel,在 receive 第一个值前就完成了所有的 send 操作。


使用缓冲 channel,需要注意 send 操作和 receive 操作的 goroutine 的执行效率,否则会影响性能。


04

select 多路复用


select 语句类似 switch 语句,有至少一个 case 分支,和一个可选的默认分支 default。每一个 case 分支指定一次通信(在一些 channel 上执行 send 操作或 receive 操作)和关联的一段代码块。


select 一直处于等待状态,直到一次通信可以符合条件执行某一个或多个 case 分支的代码块,然后 select 执行这次通信,并执行对应的 case 分支,其他的通信将不会发生,select 如果没有可以符合条件执行的 case 分支,它将永远处于等待状态。select 如果同时符合多个 case 分支执行,select 将随机选择一个 case 分支执行。


select  如果有可选默认分支 default,在没有通信可以符合条件执行某一个 case 分支时,它将执行默认分支 default 的代码块。





目录
相关文章
|
3月前
|
安全 Java 编译器
对比Java学习Go——基础理论篇
本章介绍了Java开发者学习Go语言的必要性。Go语言以简单、高效、并发为核心设计哲学,摒弃了传统的类继承和异常机制,采用组合、接口和多返回值错误处理,提升了代码清晰度与开发效率。Go直接编译为静态二进制文件,启动迅速、部署简便,其基于Goroutine和Channel的并发模型相较Java的线程与锁机制更轻量安全。此外,Go Modules简化了依赖管理,与Java的Maven/Gradle形成鲜明对比,提升了构建与部署效率。
|
2月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
201 1
|
3月前
|
存储 Java Go
对比Java学习Go——函数、集合和OOP
Go语言的函数支持声明与调用,具备多返回值、命名返回值等特性,结合`func`关键字与类型后置语法,使函数定义简洁直观。函数可作为一等公民传递、赋值或作为参数,支持匿名函数与闭包。Go通过组合与接口实现面向对象编程,结构体定义数据,方法定义行为,接口实现多态,体现了Go语言的简洁与高效设计。
|
3月前
|
存储 Java 编译器
对比Java学习Go——程序结构与变量
本节对比了Java与Go语言的基础结构,包括“Hello, World!”程序、代码组织方式、入口函数定义、基本数据类型及变量声明方式。Java强调严格的面向对象结构,所有代码需置于类中,入口方法需严格符合`public static void main(String[] args)`格式;而Go语言结构更简洁,使用包和函数组织代码,入口函数为`func main()`。两种语言在变量声明、常量定义、类型系统等方面也存在显著差异,体现了各自的设计哲学。
|
4月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
297 1
|
4月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
397 0
|
4月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
261 0
|
4月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
230 0
|
4月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
332 0
|
4月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。