美文网首页
Go语言学习之旅 4 - Go 的并发原语

Go语言学习之旅 4 - Go 的并发原语

作者: 张云飞Vir | 来源:发表于2020-03-09 22:46 被阅读0次

Go语言学习笔记 3 - Go 的并发原语

概述

连续三节的内容如下:

  • 第一节覆盖了基本语法及数据结构
  • 第二节讨论了方法与接口
  • 第三节则简单介绍了 Go 的并发原语。

Go 程

Go 程(goroutine)是由 Go 运行时管理的轻量级线程。

go 函数名

会启动一个新的 Go 程并执行这个函数。
比如:
go say("world") // 将启动一个线程来执行 say 函数

这里说"线程"其实不严谨,不过便于理解。

Go 程在相同的地址空间中运行,因此在访问共享的内存时必须进行同步。
sync 包提供了这种能力,不过在 Go 中并不经常用到,因为还有其它的办法。

func say(s string){
  for i:=0;i<5;i++ {
    //fmt.Println(time.Millisecond)
    time.Sleep(100 * time.Millisecond);
    fmt.Println(s,i)
  }
}

func main() {
  go say("jack")
  say("lucy")
}

信道

信道是带有类型的管道,你可以通过它用信道操作符 <- 来发送或者接收值。

  ch <- v    // 将 v 发送至信道 ch。
  v := <-ch  // 从 ch 接收值并赋予 v。

(“箭头”就是数据流的方向。)

和映射与切片一样,信道在使用前必须创建:

ch := make(chan int)

默认情况下,发送和接收操作在另一端准备好之前都会阻塞。这使得 Go 程可以在没有显式的锁或竞态变量的情况下进行同步。

示例:

func su(ch chan int){
  ch <- 1
  ch <- 2
}

func main() {
  ch := make(chan int)
  go su(ch)
  x := <- ch
  y := <- ch
  fmt.Println(x,y)
}

带缓冲的信道

信道可以是 带缓冲的。将缓冲长度作为第二个参数提供给 make 来初始化一个带缓冲的信道:

ch := make(chan int, 100)

仅当信道的缓冲区填满后,向其发送数据时才会阻塞。当缓冲区为空时,接受方会阻塞。

func main() {
    ch := make(chan int,2)
    ch <- 1
    ch <- 2// 缓冲区是2,此时还未堵塞。当再次写入时,就会阻塞。
    x := <- ch
    y := <- ch
    fmt.Println(x,y)
}

range 和 close

发送者可通过 close 关闭一个信道,它表示没有需要发送的值了。
接收者可以通过为接收表达式分配第二个参数来测试信道是否被关闭:若没有值可以接收且信道已被关闭,那么在执行完

v, ok := <-ch

之后 ok 会被设置为 false。

这样写个循环:

for i := range c //会不断从信道接收值,直到它被关闭。

注意:

  • 只有发送者才能关闭信道,而接收者不能。
  • 向一个已经关闭的信道发送数据会引发程序崩溃。
    注意:
  • 信道与文件不同,通常情况下无需关闭它们。
  • 只有在必须告诉接收者不再有需要发送的值时才有必要关闭,例如终止一个 range 循环。

select 语句

select 语句使一个 Go 程可以等待多个通信操作。
select 会阻塞到某个分支可以继续执行为止,这时就会执行该分支。当多个分支都准备好时会随机选择一个执行。

默认选择
当 select 中的其它分支都没有准备好时,default 分支就会执行。

为了在尝试发送或者接收时不发生阻塞,可使用 default 分支:

select {
case i := <-c:
    // 使用 i
default:
    // 从 c 中接收会阻塞时执行
}

sync.Mutex

我们已经看到信道非常适合在各个 Go 程间进行通信。
但是如果我们并不需要通信呢?比如说,若我们只是想保证每次只有一个 Go 程能够访问一个共享的变量,从而避免冲突?
这里涉及的概念叫做 互斥(mutualexclusion)* ,我们通常使用 互斥锁(Mutex) 这一数据结构来提供这种机制。

Go 标准库中提供了 sync.Mutex 互斥锁类型及其两个方法:

  • Lock
  • Unlock

我们可以通过在代码前调用 Lock 方法,在代码后调用 Unlock 方法来保证一段代码的互斥执行。
我们也可以用 defer 语句来保证互斥锁一定会被解锁。

更多学习资料

http://docscn.studygolang.com/doc/
https://go-zh.org/#
https://tour.go-zh.org/list

END

相关文章

  • Go语言学习之旅 4 - Go 的并发原语

    Go语言学习笔记 3 - Go 的并发原语 概述 连续三节的内容如下: 第一节覆盖了基本语法及数据结构 第二节讨论...

  • Go语言并发

    Go语言并发 Go语言级别支持协程,叫做goroutine Go 语言从语言层面支持并发和并行的开发操作 Go并发...

  • Go控制程序生命周期

    近期学了go语言的并发编程,掌握了 并发原语-原子锁,互斥锁,通道 并发原理 并发设计模式今天我们就来锻炼一下,如...

  • Go基础语法(九)

    Go语言并发 Go 是并发式语言,而不是并行式语言。 并发是指立即处理多个任务的能力。 Go 编程语言原生支持并发...

  • 跟我一起学习GO语言008

    本节我们来看GO语言中的并发。 我们看并发,就不得不学习goroutine,goroutine是Go语言...

  • Go并发调度

    本文是《循序渐进Go语言》的第六篇-Go并发调度。本文是学习《Go语言学习笔记》的并发调度一章,然后结合阅读源码的...

  • Go 并发原理

    Go语言是为并发而生的语言,Go语言是为数不多的在语言层面实现并发的语言;也正是Go语言的并发特性,吸引了全球无数...

  • GO语言初级学习之代码案例13 (QQ群聊)

    @(go语言 黑马)[GO语言] 并发聊天室 题目:利用Go语言高并发的特性,编写一个类似QQ群聊功能的并发聊天服...

  • Go并发

    并发和并行 Go是并发语言,而不是并行语言。(Go is a concurrent language and no...

  • Go并发

    Go语言中的并发编程 并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发,这也是Go语言流行的一个很...

网友评论

      本文标题:Go语言学习之旅 4 - Go 的并发原语

      本文链接:https://www.haomeiwen.com/subject/ddrpdhtx.html