郑州企业网站开发,做网站教程pdf,深圳代理记账多少钱,网站建设找业主签字模板文章目录 1、进程、线程2、协程3、主死从随4、启动多个协程5、使用WaitGroup控制协程退出6、多协程操作同一个数据7、互斥锁8、读写锁9、deferrecover优化多协程 1、进程、线程
进程作为资源分配的单位#xff0c;在内存中会为每个进程分配不同的内存区域 一个进程下面有多个… 文章目录 1、进程、线程2、协程3、主死从随4、启动多个协程5、使用WaitGroup控制协程退出6、多协程操作同一个数据7、互斥锁8、读写锁9、deferrecover优化多协程 1、进程、线程
进程作为资源分配的单位在内存中会为每个进程分配不同的内存区域 一个进程下面有多个线程干着不同的活儿 进程与线程好比打开360同时进行木马查杀和电脑清理360是一个进程后面两个则是两个线程 补充关于并行和并发
并发多线程同时/交替操作同一资源类并行多线程同时操作多个资源类
示意图
2、协程
协程是一种用户态的轻量级线程又称微线程、纤程是一种单线程下的并发协程中只有一个线程在执行协程的本质是个单线程 在一个单独的线程中出现IO操作时此时可控制单线程下的多个任务在另一个任务IO阻塞时将其寄存器上下文和栈保存到某个地方去切到另一个任务继续计算。如此就保证了线程最大程度的处于就绪状态执行效率变高。 协程的引入给CPU一种该线程好像是一直在计算io比较少的错觉从而会更多的将cpu的执行权限分配给我们的线程 线程是CPU控制的而协程是程序自身控制的属于程序级别的切换操作系统完全感知不到因而更加轻量级 感觉在线程的基础上再细分还是因为后面计算机在硬件上发展快了如此再做切换可以更加提升效率。
package main
import(fmtstrconvtime
)
func test(){for i : 1;i 10;i {fmt.Println(hello golang strconv.Itoa(i))//阻塞一秒time.Sleep(time.Second)}
}
func main(){//主线程go test() //开启一个协程for i : 1;i 10;i {fmt.Println(hello 9527 strconv.Itoa(i))//阻塞一秒time.Sleep(time.Second)}
}如上主线程中开启一个协程协程每1秒输出hello golang主线程每一秒输出一次hello 9527主线程和协程在同时执行且属于同一个线程主线程。运行 3、主死从随
即
主线程执行结束退出了则即使其下的协程没有执行完也要跟着陪葬当然协程如果提前在主线程之前结束那就正常自己结束就好
package main
import(fmtstrconvtime
)
func test(){for i : 1;i 1000;i {fmt.Println(hello golang strconv.Itoa(i))//阻塞一秒time.Sleep(time.Second * 1)}
}
func main(){//主线程go test() //开启一个协程for i : 1;i 10;i {fmt.Println(hello msb strconv.Itoa(i))//阻塞一秒time.Sleep(time.Second * 1)}
}4、启动多个协程
package main
import(fmttime
)
func main(){//匿名函数外部变量 闭包for i : 1;i 5;i {//启动一个协程//使用匿名函数直接调用匿名函数go func(n int){fmt.Println(n)}(i)}time.Sleep(time.Second * 2)
}5、使用WaitGroup控制协程退出
思想类似Java的计数器那些JUC辅助类用来解决主线程在子协程结束后自动结束即阻塞线程等等所有协程执行完。核心方法
//协程开始的时候加1操作
func (wg*WaitGroup) Add(delta int)//协程执行完后减一
func(wg *WaitGroup) Done()//WaitGroup为0前阻塞线程
func(wg *WaitGroup) Wait()示例
package main
import(fmtsync
)
var wg sync.WaitGroup //只定义无需赋值
func main(){//启动五个协程for i : 1 ;i 5;i {wg.Add(1) //协程开始的时候加1操作go func(n int){fmt.Println(n)wg.Done() //协程执行完成减1}(i)}//主线程一直在阻塞什么时候wg减为0了就停止wg.Wait()
}当然也可用defer关键字去减一
package main
import(fmtsync
)
var wg sync.WaitGroup
func main(){for i : 1 ;i 5;i {wg.Add(1) go func(n int){defer wg.Done() //!!!这里fmt.Println(n) }(i)}wg.Wait()
}可以最开始在知道协程次数的情况下先Add操作
package main
import(fmtsync
)
var wg sync.WaitGroup
func main(){wg.Add(5) //这里for i : 1 ;i 5;i {go func(n int){defer wg.Done()fmt.Println(n) }(i)}wg.Wait()
}注意Add的个数和协程的个数要一致。
6、多协程操作同一个数据
开一个协程去做一万次1再开一个协程去做一万次-1
package main
import(fmtsync
)
//定义一个变量
var totalNum int
var wg sync.WaitGroup //只定义无需赋值
func add(){defer wg.Done()for i : 0 ;i 100000;i{totalNum totalNum 1}
}func sub(){defer wg.Done()for i : 0 ;i 100000;i{totalNum totalNum - 1}
}func main(){wg.Add(2)//启动协程go add()go sub()wg.Wait()fmt.Println(totalNum)
}运行的结果始终不为0 多协程操作同一个数据的问题按以下1.2.3.4.5.6的步骤就发现做了一次1一次-1结果为-1 修复这个问题让一个协程执行逻辑的时候另一个协程不执行 ⇒ 互斥锁
7、互斥锁
引入sync包
//加入互斥锁
var lock sync.Mutexpackage main
import(fmtsync
)
//定义一个变量
var totalNum int
var wg sync.WaitGroup //只定义无需赋值
//加入互斥锁
var lock sync.Mutex
func add(){defer wg.Done()for i : 0 ;i 100000;i{//加锁lock.Lock()totalNum totalNum 1//解锁lock.Unlock()}
}
func sub(){defer wg.Done()for i : 0 ;i 100000;i{//加锁lock.Lock()totalNum totalNum - 1//解锁lock.Unlock()}
}
func main(){wg.Add(2)//启动协程go add()go sub()wg.Wait()fmt.Println(totalNum)
}8、读写锁
互斥锁在读多写少的场景不适合性能低下采用读写互斥但读读共享的读写锁。
//加入读写锁
var lock sync.RWMutexlock.RLock()//读锁
lock.RUnlock()示例
package main
import(fmtsynctime
)
var wg sync.WaitGroup //只定义无需赋值
//加入读写锁
var lock sync.RWMutex
func read(){defer wg.Done()lock.RLock()//如果只是读数据那么这个锁不产生影响但是读写同时发生的时候就会有影响fmt.Println(开始读取数据)time.Sleep(time.Second)fmt.Println(读取数据成功)lock.RUnlock()
}
func write(){defer wg.Done()lock.Lock()fmt.Println(开始修改数据)time.Sleep(time.Second * 10)fmt.Println(修改数据成功)lock.Unlock()
}
func main(){wg.Add(6)//启动协程 --- 场合读多写少for i : 0;i 5;i {go read()}go write()wg.Wait()
}运行发现写的时候不能读但读的时候可以共享读 9、deferrecover优化多协程
多协程工作一个协程出现panic整个程序崩溃。引入deferrecover让协程即使出现错误也不影响主线程和其他协程的执行
ackage main
import(fmttime
)
//输出数字
func printNum(){for i : 1;i 10;i{fmt.Println(i)}
}
//做除法操作
func devide(){defer func(){err : recover()if err ! nil{fmt.Println(devide()出现错误,err)}}()num1 : 10num2 : 0result : num1 / num2fmt.Println(result)
}
func main(){//启动两个协程go printNum()go devide()time.Sleep(time.Second * 5)
}运行