使用go关键字启动一个goroutine
程序员唯一需要做的
是把任务封装成一个函数
程序启动之后会创建一个主goroutine去执行(main也是一个goroutine)
package main
import("fmt""sync""runtime")
var wg sync.WaitGroup //計數器
func print(i int) {defer wg.Done() //任務完成,計數器-1fmt.Println(i)}
func main() {runtime.GOMAXPROCS(1) //默認CPU邏輯核心數,默認跑滿整個CPU// wg.Add(10)for i:=0; i<100; i++{wg.Add(1) //啟動任務,計數器+1go print(i) //啟動一個線程}wg.Wait() // 等待wg的計數器減為0}
goroutine调度模型
GMP
m:n 把m个goroutine分配给n个操作系统线程去执行
goroutine初始栈的大小是2k
runtime.GOMAXPROCS(1) 可以修改n的值
现实中并发的目的是执行任务
比如第一种任务,每个任务的执行都依赖上一个任务的结果,这种并发是没有意义的
任务链:f1() -> f2() - > f3()
比如第二种任务,某个任务的执行依赖多个任务的结果,这多个任务可以并发执行
任务链:f1()|f2()|f3() -> f4()
虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题。为了保证数据交换的正确性,必须使用互斥量对内存进行加锁,这种做法势必造成性能问题。
Go语言的并发模型是CSP(Communicating Sequential Processes),
提倡通过通信共享内存而不是通过共享内存而实现通信。
var b chan int //声明管道
b = make(chan int) //给管道开辟空间,无缓冲
b = make(chan int, 5) //带缓冲的通道,可预存5个值,存满后再放就阻塞
b <- 2 //给通道放值
var n int; n = <- b //从通道取值,方式一
n := <-b // 从通道取值,方式二
<- b //取出值扔掉
close(b) //关闭通道,关闭分为两端,读的一端和写的一端。例如: f1函数写,f1里面close,表示不能向管道里写了,但是能读。 f2函数读,f2里面close,表示不能从f2里面读了,但是能向f2里面写。
在运行中,确定不用了,要手动关闭通道。不关闭很容易造成deadlock
for i:= range b {
fmt.Println(i) //从通道里循环取值
}
小的值扔通道里直接扔值,大的值扔指针
//开启goroutine将0~100的数发送到ch1中
//开启goroutine从ch1中接收值,将该值的平方发送到ch2中
原文:https://www.cnblogs.com/staff/p/13233476.html