Go的并发编程

go语言并发模型   --   MPG
M:      machine     系统线程
P:      Processer   逻辑处理器
G:      goroutine   go语言协程

一个M会对应一个内核线程,一个M也会连接一个上下文P,一个上下文P相当于一个“处理器”
一个上下文连接一个或者多个Goroutinue。为了运行goroutine,线程必须保存上下文

运行的M和P的关系   1:1

一个调度器P 对应着一个本地队列

全局队列
本地队列满了  会把G放到全局队列中

hand off机制:
1.如果发生syscall处理的线程M0陷入阻塞状态,这个M0就会释放P
    P就转移给空闲的M1去执行,如果没有空闲的线程,就会创建一个新线程执行
2.如果系统调用结束,根据M0是否获取到P,将会对原来的G做不同处理
    a、如果有空闲的P,则获取一个P,继续执行原来的G0
    b、如果没有空闲的P,将原来的G0加入全局队列,等待被其他的P调度,M0进入缓存池睡眠

全局队列任务处理
1、P运行完成自己的本地队列任务,就会从全局队列中拿取
2、P也会周期性这个全局队列,防止全局队列的goroutinue被饿死

work stealing机制
当本线程没有可运行的G的时候,可以从全局队列中获取G;
如果全局队列中也没有,就从别的线程绑定的P那里,抽取一半的G处理

sysmon  monitor  协程  系统监控协程,监控公平性
不需要P也能执行,是一个特殊的协程,做协程监控的
在go中,一个协程,最多占用 cpu 10ms,防止其他 goroutines 饿死
任何超过10ms的协程,都会被抢占,将运行时间留给其他 goroutine
主要做协程抢占、垃圾回收
package main

import (
    "fmt"
    "time"
)

/*
go语言并发模型   --   MPG
M:      machine     系统线程
P:      Processer   逻辑处理器
G:      goroutine   go语言协程

一个M会对应一个内核线程,一个M也会连接一个上下文P,一个上下文P相当于一个“处理器”
一个上下文连接一个或者多个Goroutinue。为了运行goroutine,线程必须保存上下文

运行的M和P的关系   1:1

一个调度器P 对应着一个本地队列

全局队列
本地队列满了  会把G放到全局队列中

hand off机制:
1.如果发生syscall处理的线程M0陷入阻塞状态,这个M0就会释放P
    P就转移给空闲的M1去执行,如果没有空闲的线程,就会创建一个新线程执行
2.如果系统调用结束,根据M0是否获取到P,将会对原来的G做不同处理
    a、如果有空闲的P,则获取一个P,继续执行原来的G0
    b、如果没有空闲的P,将原来的G0加入全局队列,等待被其他的P调度,M0进入缓存池睡眠

全局队列任务处理
1、P运行完成自己的本地队列任务,就会从全局队列中拿取
2、P也会周期性这个全局队列,防止全局队列的goroutinue被饿死

work stealing机制
1.当本线程没有可运行的G的时候,可以从全局队列中获取G;
    如果全局队列中也没有,就从别的线程绑定的P那里,抽取一半的G处理

sysmon  系统监控协程,监控公平性
不需要P也能执行,是一个特殊的协程,做协程监控的,在go中,一个协程,最多占用 cpu 10ms
防止其他 goroutines 饿死,在任何超过10ms的协程,都会被抢占,将运行时间留给其他 goroutine
主要做协程抢占、垃圾回收
}
*/

// // 匿名协程
// func main() {
//  go func() {
//      i := 0
//      for {
//          i++
//          fmt.Println("子协程 i=", i)
//          time.Sleep(1 * time.Second)
//      }
//  }()

//  for i := 0; i < 3; i++ {
//      fmt.Println("主协程i=", i)
//      time.Sleep(1 * time.Second)
//  }
// }
package main

import (
    "fmt"
    "time"
)

/*
go语言并发模型   --   MPG
M:      machine     系统线程
P:      Processer   逻辑处理器
G:      goroutine   go语言协程

一个M会对应一个内核线程,一个M也会连接一个上下文P,一个上下文P相当于一个“处理器”
一个上下文连接一个或者多个Goroutinue。为了运行goroutine,线程必须保存上下文

运行的M和P的关系   1:1

一个调度器P 对应着一个本地队列

全局队列
本地队列满了  会把G放到全局队列中

hand off机制:
1.如果发生syscall处理的线程M0陷入阻塞状态,这个M0就会释放P
    P就转移给空闲的M1去执行,如果没有空闲的线程,就会创建一个新线程执行
2.如果系统调用结束,根据M0是否获取到P,将会对原来的G做不同处理
    a、如果有空闲的P,则获取一个P,继续执行原来的G0
    b、如果没有空闲的P,将原来的G0加入全局队列,等待被其他的P调度,M0进入缓存池睡眠

全局队列任务处理
1、P运行完成自己的本地队列任务,就会从全局队列中拿取
2、P也会周期性这个全局队列,防止全局队列的goroutinue被饿死

work stealing机制
1.当本线程没有可运行的G的时候,可以从全局队列中获取G;
    如果全局队列中也没有,就从别的线程绑定的P那里,抽取一半的G处理

sysmon  系统监控协程,监控公平性
不需要P也能执行,是一个特殊的协程,做协程监控的,在go中,一个协程,最多占用 cpu 10ms
防止其他 goroutines 饿死,在任何超过10ms的协程,都会被抢占,将运行时间留给其他 goroutine
主要做协程抢占、垃圾回收
}
*/

// // 匿名协程
// func main() {
//  go func() {
//      i := 0
//      for {
//          i++
//          fmt.Println("子协程 i=", i)
//          time.Sleep(1 * time.Second)
//      }
//  }()

//  for i := 0; i < 3; i++ {
//      fmt.Println("主协程i=", i)
//      time.Sleep(1 * time.Second)
//  }
// }
创建一个协程
package main

import (
    "fmt"
    "runtime"
    "time"
)

/*
协程

运行main,就是运行了一个协程,运行之初就创建一个协程
协程  --  runtime.g    结构体
*/

func main() {
    fmt.Println("hello word")
    //GOMAXPROCS    设置当前P的数量  输入0表示查询当前P的数量,输入大于0的数,表示设置P的数量
    fmt.Println(runtime.GOMAXPROCS(0)) //8
    runtime.GOMAXPROCS(9)
    fmt.Println(runtime.GOMAXPROCS(0)) //9
    go hello()                         //开启协程
    go hello2()

    //默认情况下,主协程退出,子协程也会退出
    time.Sleep(2 * time.Second)
}

func hello() {
    fmt.Println("hello start...")
    fmt.Println("hello end...")
}

func hello2() {
    fmt.Println("hello2 start...")
    time.Sleep(1 * time.Second)
    fmt.Println("hello2 end...")
}
匿名协程
package main

import (
    "fmt"
    "time"
)

// 匿名协程
func main() {
 go func() {
     i := 0
     for {
         i++
         fmt.Println("子协程 i=", i)
         time.Sleep(1 * time.Second)
     }
 }()

 for i := 0; i < 3; i++ {
     fmt.Println("主协程i=", i)
     time.Sleep(1 * time.Second)
 }
}
协程异常处理
//协程异常处理
//go语言中,如果一个协程崩溃了,所有协程都会退出

package main

import (
    "fmt"
    "time"
)

func except_test() {
 defer func() {
     if r := recover(); r != nil {
         fmt.Println("something error!", r)
     }
 }()

 fmt.Println("this is except_test")
 lst := []int{1, 2, 3}
 fmt.Println(lst[3])
}

func except_test2() {
 fmt.Println("this is except_test2")
 time.Sleep(1 * time.Second)
 fmt.Println("except_test2 end...")
}

func main() {
 fmt.Println("this is main")
 go except_test()
 go except_test2()
 time.Sleep(2 * time.Second)
 fmt.Println("end...")
}
多个协程下载照片
// 多个协程下载多张图片

package main

import (
    "fmt"
    "time"
)

func Download_photo() {
 fmt.Println("下载照片")
}

func main() {
 for i := 0; i < 5; i++ {
     go Download_photo()
     time.Sleep(1 * time.Second)
 }
}
sync锁机制
package main

import (
    "fmt"
    "sync"
    "time"
)

/*
go语言sync包  提供了一些用于并发操作的同步原语
常见的锁机制
    互斥锁     mutex
    条件变量    cond
    WaitGroup   阻塞
*/

var wg sync.WaitGroup
var num = 10

var mutex sync.Mutex

func main() {
    wg.Add(3)
    go test(&wg)
    go test(&wg)
    go test(&wg)
    wg.Wait() //主协程等待子协程
    fmt.Println("执行结束")
}

func test(wg *sync.WaitGroup) {
    defer wg.Done()
    mutex.Lock()
    time.Sleep(1 * time.Second)
    fmt.Println("this is test")
    num += 1
    fmt.Println("num:", num)
    mutex.Unlock()
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值