基础知识
在学习golang的Goroutine和channel之前,先回顾一下最基本的并发知识
1s = 1000ms =1000000us = 1000000000ns
并行: 借助多核Cpu实现。
并发: 多个计算任务顺序执行,轮换使用cpu时间轮片
进程并发 :
程序 : 编译成功得到的二进制文件 占用 磁盘空间 。 死的
进程 : 运行起来程序。占用系统资源
线程并发:
线程:LWP轻量级的 进程。 最小的执行单位
进程:最小的系统资源分配单位
同步():
协同步调。规划先后顺序。
线程同步机制:
互斥锁(互斥量) :建议锁。拿到锁以后,才能访问数据,没有拿到锁的线程,阻塞等待。等待拿锁的线程释放锁。
读写锁: 一把锁(读属性、写属性)。写独占,读共享。写锁优先级高。
协程并发:
协程 (coroutine) 也叫清凉级线程
提高程序执行效率
Goroutine :go 程
创建与进程中。直接使用go关键词,放置于函数调用前面,产生一个go程 。并发。
下面是一个Goroutine的基本用法
package main
import (
"fmt"
"time"
)
func newTask() {
i := 0
for {
i++
fmt.Printf("new goroutine: i = %d\n", i)
time.Sleep(1 * time.Second) //延时1s
}
}
func main() {
//创建一个 goroutine,启动另外一个任务
go newTask()
i := 0
//main goroutine 循环打印
for {
i++
fmt.Printf("main goroutine: i = %d\n", i)
time.Sleep(1 * time.Second) //延时1s
}
}
Goroutine的特性【特性】:
主go程结束,子go程随之退出。
runtime.Gosched() :出让当前go程序所占用的cpu时间片。当再次获得cpu时候,从出让位置继续恢复。
runtime.Goexit() :
return :返回当前函数调用到调用者那里去。return之前的defer注册生效
Goexit()结束调用该函数的当前go程。Goexit()之前注册的defer都生效
runtime.GOMAXPROCS(1) //将cpu设置为单核
设置当前进程使用的最大cpu核数。返回上一次调用成功的设置值。首次调用返回默认值
runtime.GOROOT
channel :
这是一种数据类型,对应一个 “管道” (通道)
goroutine运行在相同的地址空间,因此访问共享内存必须做好同步。goroutine奉行--通过通信来共享内存,而不是共享内存来通信
引用类型channel可用于多个goroutine通讯。其内部实现了同步,确保并发安全
channel 的定义:make(chan 在channel中传递的参数类型,容量) 容量 = 0: 无缓冲channel,容量>0:有缓冲channel
eg: make(chan int) 或 make(chan string ,0)
补充知识点 :每当有一个进程启动时,系统会自动打开三个文件:标准输入、标准输出、标准错误。 ----stdin、stdout、stderr
当运行结束收,操作系统自动关闭三个文件
下面是channel的一个基本应用(打印)
package main
import (
"fmt"
"time"
)
func printer(s string){
for _,ch:= range s {
fmt.Printf("%c",ch)
time.Sleep(300*time.Millisecond)
}
}
//全局定义channel,用来完成数据同步
var channel = make(chan int)
//定义两个人使用打印机
func person1(){ //person先执行
printer("hello")
channel <- 675 //只要类型符合,随便写什么 ,没人读之前,channel一直是阻塞
}
func person2(){ //person 后执行 <-channel 读数据,保证数据流向
<-channel
printer("world")
}
func main(){
go person1()
go person2()
for {
;
}
}
channel的两个端:
一端:写端(传入端) chan <-
另一端 :读端(传出端) <- chan
要求:读端和写端必须同时满足条件,才能在channel上进行数据流动,否则阻塞