并发编程:

1.概念
并发:同一时间段内执行多个操作
并行:同一时刻执行多个操作

多线程:
A.线程是由操作系统进行管理也就是处于内核态。
B.线程之间进行切换,需要发生用户态到内核态的切换。
c.当系统中运行大量线程,系统会变的非常慢。
D.用户态的线程,支持大量线程创建。也叫协程或 goroutine

 

2.goroutine 实现
通过 go 关键字来开启 goroutine 即可

package main
import (
        "fmt"
        "time"
)
func say(s string) {
        for i := 0; i < 5; i++ {
                time.Sleep(100 * time.Millisecond)
                fmt.Println(s)
        }
}

func main() {
        go say("world") //开启一个新的线程进行执行
        say("hello")
}

 

3.多核控制
A.通过 runtime 包进行多核设置
B.通过 GOMAXPROCS 设置当前程序运行时占用的cpu核数,可通过这个来控制程序处理性能
C.通过 NumCPU 获取当前系统的cpu全部核数(逻辑处理器)

package main
import (
        "fmt"
        "runtime"
)
 
func main() {
      cpu := runtime.NumCPU() 
      runtime.GOMAXPROCS(cpu) //默认情况下,1.6之前版本使用1个核心,后面新版本则使用所有核心
}

 

通道:

1.定义

通道本质上就是一个队列,是一个容器,可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯

//定义,需要只定容器中元素的类型
var channel_name chan type

//初始化,需要初始化后才可以使用 
默认情况下,通道是不带缓冲区的。发送端发送数据,同时必须有接收端相应的接收数据 ,否则数据入队会等待阻塞

channel_name = make(chan,type) 

//有缓冲区(有长度)
带缓冲区的通道允许发送端的数据发送和接收端的数据获取处于异步状态,就是说发送端发送的数据可以放在缓冲区里面,
可以等待接收端去获取数据,而不是立刻需要接收端去获取数据。不过由于缓冲区的大小是有限的,所以还是必须有接收端
来接收数据的,否则缓冲区一满,数据发送端就无法再发送数据了(发生阻塞,当通道里面没有数据,进行取数据的时候也会发生阻塞)。

channel_name = make(chan,type,len) 

//入队
channel_name <- value

//出队
val := <- channel_name

2.线程同步,等待其他线程执行后再退出程序

方法一:使用无缓冲区通道
func hello(c chan bool){
 time.Sleep(5*time.Second)
 fmt.Println("hello goroutine")
 c<-true
}
func main(){
 var exitChan chan bool 
 exitChan = make(chan bool) //无缓冲区通道,用来做阻塞等待
 go hello(exitChan)
 fmt.Println("main thread")
 <-exitChan
}

方法二:Waitgroup (推荐)
func process (i int ,wg *sync.WaitGroup ){ //WaitGroup是一个结构体,属于引用类型,所以如果传参要改值的话需要传指针
 time.Sleep (2time .Second )
 wg.Done ()//完成一个计数
}

func main(){
 no:=3
 var wg sync.WaitGroup  //定义WaitGroup
 for 0 ;i < no ;i++ {
  wg.Add (1) //增加计数
  go process (i,&wg)
 }
 wg.Wait()//等待计数全部完成,就会返回
}

3.单向chan,可用来权限控制

//只写
func sendData(sendch chan <- int){
 sendch <-10
}
//只读
func readData(sendch <- chan  int){
 data := <- sendch 
}

4.管道关闭

//当管道不需要用的时候可以关闭
close(channel_name)

//可通过 ok 判断管道是否关闭
for {
v,ok := channel_name
if ok == false {
  break
 }
}

5.for range 遍历

for v := channel_name range{
}