并发

并发 #

goroutine #

使用 goroutine #

语法为 go 方法名()

import "time"

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

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

Channel #

概述 #

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

建立 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")
}
沪ICP备17055033号-2