并发编程
2020-03-24 本文已影响0人
isuntong
介绍
线程:轻量级进程
携程:轻量级线程
并发
协程
mac活动监视器=任务管理器
线程:进程中的执行路径
package main
import "fmt"
//9
func main() {
/*
一个goroutine打印数字,另外一个goroutine打印字母,观察运行结果
*/
//1. 先创建并启动子goroutine,执行printNum()
go printNum()
//2. main打印字母
for i:=1;i<=100;i++ {
fmt.Printf("\t主goroutine打印字母:A %d\n",i)
}
fmt.Println("main over...")
}
func printNum(){
for i:=1;i<=100;i++ {
fmt.Printf("子goroutine打印数字:%d\n",i)
}
}
主goroutine结束,程序就结束了,不管子goroutine,可以用管道通信
与函数不同,所以写了返回值也没有用
启动多个goroutine
并发模型
runtime包
类似与虚拟机,管理内存
package main
import (
"fmt"
"runtime"
"time"
)
//10
func main() {
//获取goroot目录
fmt.Println("GOROOT---->",runtime.GOROOT()) //GOROOT----> /usr/local/go
//获取操作系统
fmt.Println("os/platform---->",runtime.GOOS) //os/platform----> darwin,mac系统
//获取逻辑cpu的数量
fmt.Println("逻辑CPU的数量---->",runtime.NumCPU()) //逻辑CPU的数量----> 8
//设置cpu数量,不要乱写,写当前逻辑cpu数量就行,最好写在init函数
//n := runtime.GOMAXPROCS(16)
//fmt.Println(n)
//gosched让出当前时间片,让别的goroutine先执行
go func(){
for i := 0; i < 5; i++ {
fmt.Println("goroutine...")
}
}()
for i := 0; i < 5; i++ {
//让出时间片,先让别的goroutine执行
runtime.Gosched()
fmt.Println("main...")
}
//创建goroutine
go func() {
fmt.Println("goroutine开始")
//调用fun
fun()
fmt.Println("goroutine结束")
}()
//睡一会
time.Sleep(3 * time.Second)
}
func fun(){
defer fmt.Println("defer...")
// return //终止函数
runtime.Goexit() //终止当前的goroutine
fmt.Println("fun函数")
}
临界资源的安全问题
package main
import (
"fmt"
"time"
)
//11
func main() {
/*
临界资源
*/
a := 1
go func() {
a = 2
fmt.Println("goroutine中a:",a)
}()
a = 3
time.Sleep(1)
fmt.Println("main goroutine...",a)
}
package main
import (
"fmt"
"math/rand"
"time"
)
//11
func main() {
/*
临界资源
*/
a := 1
go func() {
a = 2
fmt.Println("goroutine中a:",a)
}()
a = 3
time.Sleep(1)
fmt.Println("main goroutine...",a)
/*
4个goroutine,模拟4个售票口
*/
go saleTickets("售票口1")
go saleTickets("售票口2")
go saleTickets("售票口3")
go saleTickets("售票口4")
time.Sleep(5 * time.Second)
}
//全局变量
var ticket = 10
func saleTickets(name string) {
for{
if ticket > 0 {
rand.Seed(time.Now().UnixNano())
time.Sleep(time.Duration(rand.Intn(1000))*time.Millisecond)
fmt.Println(name,"售出",ticket)
ticket--
}else {
fmt.Println(name,"售罄,没有票了。。")
break
}
}
}
不鼓励通过共享内存通信,鼓励通过通信来共享内存
channel
sync包下的WaitGroup同步等待组
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup //创建同步等待组的对象
//11
func main() {
/*
waitgroup:同步等待组
Add(),设置等待组中要执行的子 goroutine 的数量
Wait(),让主goroutine等待
*/
wg.Add(2)
go fun1()
go fun2()
//无输出
fmt.Println("main进入阻塞,等待wg的子groutine结束")
wg.Wait()
fmt.Println("main阻塞解除")
}
func fun1(){
for i := 1; i < 10; i++ {
fmt.Println("fun1打印 a", i)
}
wg.Done() //给wg等待组count数值减1 == add(-1)
}
func fun2(){
defer wg.Done()
for i := 1; i < 10; i++ {
fmt.Println("\tfun2打印 b", i)
}
}
如果没有wg.Done()
如果是1,随便抓一个
互斥锁
互斥锁、读写锁
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
var wg sync.WaitGroup
//13
func main() {
/*
4个goroutine,模拟4个售票口
*/
wg.Add(4)
go saleTickets2("售票口1")
go saleTickets2("售票口2")
go saleTickets2("售票口3")
go saleTickets2("售票口4")
wg.Wait()
fmt.Println("main over")
}
//全局变量
var ticket = 10
var mutex sync.Mutex //创建锁
func saleTickets2(name string) {
rand.Seed(time.Now().UnixNano())
defer wg.Done()
for{
//上锁
mutex.Lock()
if ticket > 0 {
time.Sleep(time.Duration(rand.Intn(1000))*time.Millisecond)
fmt.Println(name,"售出",ticket)
ticket--
}else {
mutex.Unlock() //条件不满足也要解锁
fmt.Println(name,"售罄,没有票了。。")
break
}
//解锁
mutex.Unlock()
}
}
建议使用defer语句解锁
读写锁
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
var rwMutex *sync.RWMutex
//14
func main() {
/*
读写锁
*/
rwMutex = new(sync.RWMutex)
//wg.Add(2)
//
////读操作可以同时进行
//go readData(1)
//go readData(2)
wg.Add(3)
go writeData(1)
go readData(2)
go writeData(3)
wg.Wait()
fmt.Println("main over")
}
func writeData(i int){
defer wg.Done()
fmt.Println(i,"开始写:write start。。")
rwMutex.Lock() //读操作上锁
fmt.Println(i,"正在写")
time.Sleep(1 * time.Second)
rwMutex.Unlock() //读操作解锁
fmt.Println(i,"写结束:write over")
}
func readData(i int){
defer wg.Done()
fmt.Println(i,"开始读:read start。。")
rwMutex.RLock() //读操作上锁
fmt.Println(i,"正在读取")
time.Sleep(1 * time.Second)
rwMutex.RUnlock() //读操作解锁
fmt.Println(i,"读结束:read over")
}