go语言并发编程

goroutine

轻量级 线程
非抢占式多任务处理,由协程主动交出控制权
编译器/解释器/虚拟机层面的多任务

使用go关键字

//检测数据冲突
go run -race main.go

channel
goroutine之间通信 不要通过共享内存来通信;通过通信来共享内存

chan<- int 表示只发送不能接收
<-chan int 表示只接收不能发送

所有的并发问题 都可以用一致的、简单的既定的模式来规避。所有可能的话,将变量限定在goroutine内部,如果是多个goroutine都需要访问的变量,使用互斥条件来访问

go的调度器,当一个goroutine调用了time.Sleep等 阻塞时,调度器会使其进入休眠并开始执行另一个goroutine直到时机到了再去唤醒第一个goroutine。这种调度不需要进入内核的上下文,所以比线程的代价低

几个 runtime包中处理goruntine的函数

Goexit

退出当前执行的goroutine,但是defer函数还会继续调用

Gosched

让出当前goroutine的执行权限,调度器安排其他等待的任务运行,并在下次某个时候从该位置恢复执行。

NumCPU

返回 CPU 核数量

NumGoroutine

返回正在执行和排队的任务总数

GOMAXPROCS

用来设置可以并行计算的CPU核数的最大值,并返回之前的值。

example

chan 的方向

package main

import "fmt"

func main() {
	pings := make(chan string, 1)
	pongs := make(chan string, 1)
	ping(pings, "password message")
	pong(pings, pongs)
	fmt.Println(<-pongs)
}

//pings 只能用来发送channel
func ping(pings chan<- string, msg string) {
	pings <- msg
}

//pings 只能用来接收channel
func pong(pings <-chan string, pongs chan<- string) {
	msg := <-pings
	pongs <- msg
}

select

package main

import (
	"fmt"
	"time"
)

func main() {

	c1 := make(chan string)
	c2 := make(chan string)

	go func() {
		time.Sleep(time.Second * 1)
		c1 <- "one"
	}()

	go func() {
		time.Sleep(time.Second * 1)
		c2 <- "two"
	}()

	for i := 0; i < 2; i++ {
		select {
		case msg1 := <-c1:
			fmt.Println("received", msg1)
		case msg2 := <-c2:
			fmt.Println("received", msg2)
		}
	}

}