Go并发

作者: LightiSnow | 来源:发表于2020-02-05 15:45 被阅读0次

简介

Go语言调度器在操作系统之上,将操作系统的线程与语言运行时的逻辑处理器绑定,并在逻辑处理器上运行goroutine。

Go语言的并发同步模型来自一个叫做通信顺序进程(Communicating Sequential Processes,CSP)的范型。CSP是一种消息传递模型。通过在goroutine之间传递数据来传递消息,而不是对数据进行加锁来实现同步访问。

用于在goroutine之间同步和传递数据的关键数据类型叫做通道

在1.5版本上,Go语言的运行时默认会为每个可用的物理处理器分配一个逻辑处理器。

并发与并行

  • 操作系统、逻辑处理器和本地运行队列之间的关系

如果创建一个goroutine并准备运行,这个goroutine就会被放到调度器的全局运行队列中。之后,调度器就将这些队列中的goroutine分配给一个逻辑处理器,并放到这个逻辑处理器对应的本地运行队列中。本地运行队列中的goroutine会一直等待知道自己被分配的逻辑处理器执行。

如果一个 goroutine 需要做一个网络 I/O 调用,流程上会有些不一样。在这种情况下,goroutine
会和逻辑处理器分离,并移到集成了网络轮询器的运行时。一旦该轮询器指示某个网络读或者写操作已经就绪,对应的 goroutine 就会重新分配到逻辑处理器上来完成操作。

调度器对可以创建的逻辑处理器的数量没有限制,但语言运行时默认限制每个程序最多创建 10 000 个线程。这个限制值可以通过调用 runtime/debug 包的 SetMaxThreads方法来更改。如果程序试图使用更多的线程,就会崩溃。

  • 并行(parallelism)与并发(concurrency)的区别

并行是让不同的代码片段同时在不同的物理处理器上执行。并行的关键是同时做很多事情,而并发是指同时管理很多事情,这些事情可能只做了一半就被暂停去做别的事情了。

如果想让goroutine并行,必须使用多于一个逻辑处理器。

竞争状态

go build -race可以用来检查竞争状态。

$ go build -race
$ ./listing09.exe
==================
WARNING: DATA RACE
Read at 0x0000006072f8 by goroutine 7:
  main.incCounter()
      E:/code/chapter6/listing09/listing09.go:40 +0x76

Previous write at 0x0000006072f8 by goroutine 6:
  main.incCounter()
      E:/code/chapter6/listing09/listing09.go:49 +0x97

Goroutine 7 (running) created at:
  main.main()
      E:/code/chapter6/listing09/listing09.go:26 +0x90

Goroutine 6 (finished) created at:
  main.main()
      E:/code/chapter6/listing09/listing09.go:25 +0x6f
==================
Final Counter: 4
Found 1 data race(s)

锁住共享资源

  • 原子函数
atomic.AddInt64(&counter, 1)
atomic.LoadInt64(&counter, 1)
atomic.StoreInt64(&counter, 1)
  • 互斥锁
mutex.Lock()
{
    ...// 代码块,创建临界区,同一时刻,只有一个goroutine可以进入临界区
}
mutex.Unlock()

通道

当一个资源需要在goroutine之间共享时,通道在goroutine之间架起了一个管道,并提供了确保同步交换数据的机制。声明通道时,需要指定将要被共享的数据的类型。可以通过通道共享内置类型、命名类型、结构类型和引用类型的值或指针。

使用内置函数make创建通道,在创建有缓冲通道时,第二个参数用来指明缓冲去的大小

// 无缓冲的整型通道
unbuffered := make(chan int)

// 有缓冲的字符串通道
buffered := make(chan string, 10)

// 通过通道发送一个字符串
buffered <- "Gopher"

// 从通道接受一个字符串
value := <- buffered
  • 无缓冲的通道

接受前没有能力保存任何值,要求发送的goroutine和接受的goroutine同时准备好,才能完成发送和接受的操作。如果两个goroutine没有同时准备好,通道会导致先执行发送或接受操作的goroutine阻塞等待。这种对通道进行发送和接受的行为本身就是同步的。

  • 有缓冲的通道

和无缓冲通道最大的区别是:无缓冲的通道保证进行发送和接受的goroutine会在同一时间进行数据交换;有缓冲的通道没有这种保证。通道关闭后,goroutine依旧可以从通道接受数据,但是不能在向通道里发送数据。

相关文章

  • Go语言并发

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

  • Go基础语法(九)

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

  • Go并发模型:并发协程chan的优雅退出

    Go并发模型:并发协程chan的优雅退出 go chan的使用

  • Go并发

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

  • 第14章-并发性Concurrency

    并发性Concurrency 1.1 什么是并发 Go是并发语言,而不是并行语言。在讨论如何在Go中进行并发处理之...

  • Golang(十四) 并发性Concurrency

    并发性Concurrency 1.1 什么是并发 Go是并发语言,而不是并行语言。在讨论如何在Go中进行并发处理之...

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

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

  • Learn Golang in Days - Day 16-Go

    Learn Golang in Days - Day 16-Go并发 简介 go语言支持并发,只需要使用go关键字...

  • day08-go.GPM

    当别人到go为什么支持高并发,或者问为什么go本身对并发编程友好?以及go与Java对比的并发对比 正确回答: 在...

  • Go Goroutine

    协程并发 Go并发 什么是goroutine

网友评论

      本文标题:Go并发

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