golang基础(3)https://developer.aliyun.com/article/1530655
二 go进阶
1. 并发vs并行
线程其实它是比较系统里面比较昂贵的系统资源,然后它属于内核态,然后它的创建切换停止都属于很重的系统操作
go语言一次可创建上上万左右的协程
1.2 协程之间通信
提倡通过通信共享内存而不是通过共享内存而通信
1.3 Channel
缓冲通道缓冲缓冲通道,它们的一个区别是什么呢?我们可以看下面的一个图,第一个是无缓冲通道的。
然后其实使用无法中断的一个贡献值,它会导致发送的路径和接收的路径是同步的然后其实使用无法中断的一个贡献值,它会导致发送的路径和接收的路径是同步的
只要数据一直不被拿走也会一直被阻塞
package main func CalSquare() { src := make(chan int) dest := make(chan int, 3) go func() { defer close(src) for i := 0; i < 10; i++ { src <- i } }() go func() { defer close(dest) for i := range src { dest <- i * i } }() //可以迭代不断操作channel for i := range dest { println(i) } } func main() { CalSquare() }
如果管道的接收方的那个gorouting 没有接收到信息就会阻塞,当chan 中传来数据时就会发送唤醒信号进行唤醒,不读也会发生阻塞
从而实现了gorouting之间的通信
生产者的通道是无缓冲,因为生产者较为简单速度较快,消费者通道设置缓冲可以避免消费者消费速度问题影响生产(我不需要等你消费完再生产了)
在Go语言中,()
表示立即执行一个函数。这被称为函数调用表达式。在这种表达式中,函数会被立即执行,并且表达式的结果是该函数的返回值(如果有的话)。
go func() {…}()
在你提供的代码片段中,go func() {...}()
是一个函数调用表达式。让我们逐步解释它:
go
关键字:表示要创建一个新的Go协程来执行函数体中的代码,即异步地执行该函数。func() {...}
:这是一个匿名函数(没有函数名),也称为闭包。在这里,我们定义了一个匿名函数,它接收一个参数,并在函数体内进行操作。()
:这是函数调用操作符,表示要立即调用前面定义的匿名函数。
为什么我们要在匿名函数后面加上()
呢?因为我们想立即执行这个匿名函数。在这个例子中,go func() {...}()
会创建一个新的Go协程并立即执行匿名函数的代码。这样,该匿名函数就会在一个单独的Go协程中运行,并且不会阻塞当前的执行流程,即它会在后台异步地执行。
总结:在Go语言中,通过在匿名函数后面加上()
,我们可以立即执行这个匿名函数。通过在匿名函数前面加上go
关键字,我们可以在一个新的Go协程中异步地执行这个函数,而不会阻塞当前的执行流程。这样可以实现并发执行,提高程序的并发性能。
<- 在go中表示什么
ChatGPT
在Go语言中,<-
是通道操作符,用于发送和接收数据到/从通道。它的意义取决于它是用于通道的发送操作还是接收操作。
- 发送操作:
- 在
chan <- value
的形式中,<-
用于将value
发送到通道chan
。 - 例如:
ch <- 42
表示将整数值42
发送到通道ch
中。
- 接收操作:
- 在
value := <-chan
的形式中,<-
用于从通道chan
接收数据,并将接收到的值赋给value
变量。 - 例如:
x := <-ch
表示从通道ch
接收数据,并将其赋值给变量x
。
除了用于通道的发送和接收操作外,<-
还可以用于关闭通道。
- 关闭通道:
- 在
close(chan)
的形式中,close
是一个内置函数,用于关闭通道。 - 例如:
close(ch)
表示关闭通道ch
。
需要注意的是,在接收操作中,<-
的左边是变量名,右边是通道名。而在发送操作中,<-
的左边是通道名,右边是要发送的值。这个语法设计是为了与C语言中的指针操作类似,并且便于理解通道的数据流向。
总结:在Go语言中,<-
是通道操作符,用于发送和接收数据到/从通道。它可以表示通道的发送操作、接收操作,以及关闭通道。
channel与select
单流程下go只能监控一个channel的状态,select可以完成监控多个channel的状态
package main import "fmt" func fib(c, quit chan int) { x, y := 1, 1 for { select { //如果c可写 case c <- x: x = y y = x + y //如果quit可读 case <-quit: fmt.Println("quit") return } } } func main() { c := make(chan int) quit := make(chan int) go func() { for i := 0; i < 10; i++ { fmt.Println(<-c) } quit <- 0 }() fib(c, quit) }
1.4 并发安全 Lock
var ( x int64 lock sync.Mutex ) 解释
ChatGPT
这段代码使用Go语言中的var
关键字来声明了两个变量,x
和lock
。
- x:
x
是一个64位有符号整数(int64)类型的变量。- 在这里,变量
x
被声明为全局变量(在函数体外部声明的变量称为全局变量),并且由于没有初始化值,Go语言会将其初始化为int64
类型的零值,即0
。 - 作为全局变量,
x
的作用域将是整个包(文件)范围内,可以在包中的任何函数中访问和修改它的值。
- lock:
lock
是一个互斥锁(sync.Mutex
)类型的变量。- 互斥锁是用于多个Go协程之间的同步的一种机制。当一个协程获得了互斥锁后,其他协程将被阻塞在该锁上,直到持有锁的协程释放它。
- 在这里,
lock
被声明为全局变量,因此可以在整个包范围内共享,并在不同的函数中使用。 - 互斥锁一般用于保护共享资源的并发访问,确保在任意时刻只有一个协程能够访问或修改共享资源,从而避免竞态条件和数据竞争问题。
总结:这段代码声明了一个全局的int64
类型变量x
和一个全局的互斥锁lock
,用于在包内的多个函数中共享和保护资源。int64
类型的变量x
被初始化为零值,而互斥锁lock
默认为零值,表示未加锁状态。
1.5 WaitGroup
package main import "fmt" func CalSquare() { src := make(chan int) dest := make(chan int, 3) go func() { defer close(src) for i := 0; i < 10; i++ { src <- i } }() go func() { defer close(dest) for i := range src { dest <- i * i } }() for i := range dest { println(i) } } func hello(i int) { println("hello gorouting" + fmt.Sprint(i)) } func main() { CalSquare() }
golang基础(5)https://developer.aliyun.com/article/1530659