go 速学 - 15 - 并发

目录

摘要

goroutine,Channel 作用,单向与双向 channel,生产者与消费者模式,缓存与无缓存 channel,同步与异步,WaitGroup,Select, timeout

并发

goroutine

使用 goroutine

语法为 go 方法名()

import "time"

func test01() {
    fmt.Println("test01...")
}
go test01() //test01...
time.Sleep(1 * time.Second)

以上如果不调用 Sleep() 方法则 main() 方法结束后程序就结束了,其它线程无法得到执行的机会

Channel

概述

  • Channel 是引用类型
  • Channel 可以用于阻塞线程
  • 可以设置缓存,缓存默认为0
  • 缓存没有填满之前不会阻塞
  • Channle 的主要作用是消息传递和同步

建立 Channel

语法

  • 创建 Channel
    make(chan type, cacheSize)
  • 关闭 Channel
    close(ch)
  • 向 Channel 中存入数据
    ch<-data
  • 从 Channel 中读取数据
    <-ch

单向 Channel

默认创建的 Channel 为双向的,也可以创建只读或只写的单向 Channel。
单向 Channel 一般用于消息传递。

只写 Channel

var ch1 chan<- int

只读 Channel

var ch2 <-chan int

生产者,消费者示例

func producer(queue chan<- int) {
    for i := 0; i < 10; i++ {
        queue <- i
        fmt.Println("send:", i)
    }
    close(queue)
}
func consumer(queue <-chan int) {
    for i := 0; i < 10; i++ {
        v := <-queue
        fmt.Println("receive:", v)
    }
}

queue := make(chan int, 1)
go producer(queue)
go consumer(queue)
time.Sleep(1 * time.Second)

使用没有缓存的 Channel

没有缓存的 Channel 又称为同步 Channel,主要用于同步操作。

接收方会一直阻塞直到有数据到来。如果 channel 是无缓冲的,发送方会一直阻塞直到接收方将数据取出。

func test02(ch chan bool) {
    fmt.Println("test02...")
    fmt.Println("waiting...")
    ch <- true
    close(ch)
}
ch := make(chan bool)
go test02(ch)
//以下代码中 ch 阻塞线程等待输入,直到 test02()中 true被输入到 channel 中
<-ch //test02... waiting...

ch = make(chan bool)
go test02(ch)
for v := range ch {
    fmt.Println(v)
}
<-ch //test02...waiting...true

使用有缓存的 Channel

接收方会一直阻塞直到有数据到来。如果 channel 带有缓冲区,发送方会一直阻塞直到数据被拷贝到缓冲区;如果缓冲区已满,则发送方只能在接收方取走数据后才能从阻塞状态恢复。

func test05(ch chan bool) {
    fmt.Println("test05...")
    fmt.Println("waiting test05...")
    ch <- true
    fmt.Println("waiting 01...")
    fmt.Println("waiting 02...")
    fmt.Println("waiting 03...")
    close(ch)
}
ch = make(chan bool, 10)
go test05(ch)
d := <-ch
fmt.Println("d", d) //test05... waiting test05... waiting01 waiting02 waiting03 true

多线程同步

开启多线程

开启多线程使用如下代码

import "runtime"
runtime.GOMAXPROCS(runtime.NumCPU())

使用 Channel 同步

func test03(ch chan bool, index int) {
    a := 1
    for i := 0; i < 1000; i++ {
        a += i
    }
    fmt.Println("test03", index, a)
    ch <- true
}

ch = make(chan bool, 10)
for i := 0; i < 10; i++ {
    go test03(ch, i)    //向 Channel 写10次
}
for i := 0; i < 10; i++ {
    <-ch                //从 Channel 读10次
}

使用 WaitGroup 同步

func test04(wg *sync.WaitGroup, index int) {
    a := 1
    for i := 0; i < 1000; i++ {
        a += i
    }
    fmt.Println("test04", index, a)
    wg.Done()
}

wg := sync.WaitGroup{}
wg.Add(10)
for i := 0; i < 10; i++ {
    go test04(&wg, i)
}
wg.Wait()

Select

概述

  • 可按随机顺序同时处理多个 channel
  • 可用 空 channel 阻塞 main 线程
  • 可设置 timout 时间

使用 Select

定义三个 Channel

c1, c2 := make(chan int), make(chan string) //进行数据传输
o := make(chan bool)    //进行阻塞

定义 goroutine

go func() {
        for {
            select {
            case v, ok := <-c1:
                if !ok {
                    o <- true
                    break
                }
                fmt.Println("c1", v)
            case v, ok := <-c2:
                if !ok {
                    o <- true
                    break
                }
                fmt.Println("c2", v)
            }
        }
    }()
c1 <- 1
c2 <- "hi"
c1 <- 2
c2 <- "hello"

close(c1)
close(c2)

<-o
//c1 1 -> c2 hi -> c1 2 -> c2 hello

设置 Timeout

select {
case <-time.After(2 * time.Millisecond):
    fmt.Println("timeout")
}

本文来自:CSDN博客

感谢作者:mrseasons

查看原文:go 速学 - 15 - 并发

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。