1、并发的含义
并发与并行的区别:
并发:逻辑上具备同时处理多任务的能力(由程序的逻辑实现决定)
并行:物理上在同一时刻执行多个并发任务(由的处理器核数决定)
实际的单核处理器在处理任务的时候基本都是以间隔方式切换执行(时间片调度),并行是并发程序在设计的理想执行模式。
任务可以并行执行其中多线程和多进程是基本条件。
然而在单线程中引入了一个比线程还轻量级的运行单元,协程(coroutine)实现并发。
如果处理器为单核单线程,虽然一次只可以处理一个任务,但是并发的程序设计(使用协程)不但可以减少多线程带来的资源开销,也可以减少阻塞的时间占比,提高执行效率
(协程在内部执行时是串行,并且可以控制调度(程序内部实现),不需要进行同步处理,提高了并发安全)
实现并发的三种程序实现方式:
多进程:主要用于分布式,负载均衡,减轻单进程垃圾回收压力(开销大,程序健壮,切换麻烦)
多线程:抢占更多的cpu资源,(开销相对较小,并发量大于进程)
多协程:提高cpu时间片利用率(开销更小,并发量更大)
更多的时候程序是使用这三种方式组合的方式实现的。
【Golang的并发与goroutine】2、Golang中的goroutine
Goroutine类似于coroutine但是又区别于coroutine,因为在go语言中在执行一个程序时会先创建多个线程用于执行并发任务,并且又在多线程的基础上进行多goroutine的并发设计,用于提高程序的执行效率
goroutine更像线程和协程的结合体
golang中在函数的调用前加上关键字go即可创建并发任务,新建的任务会被添加到任务队列中而不是立即去执行,当前流程不会被阻塞。
在程序中每个任务单元除了会保存函数指针,调用参数外,系统都会分配栈内存空间。系统默认以MB为单位,goroutine自定义的初始栈仅为2kb,因此golang有利于千万的并发。
在golang中goroutine,sync.WaitGroup,runtime.GOMAXPROCS的联合使用
package mainimport (
"fmt"
"math"
"runtime"
"sync"
)func count(){
x := 0;
for i:=0;
i
与线程不同的是goroutine创建的任务单元无法设置优先级,并且无法获取编号,没有局部存储(TLS),甚至连返回值有时也会被抛弃。这些功能除了优先级,其他都可实现
package mainimport (
"fmt"
"sync"
)func main(){
var wg sync.WaitGroup
var gs [5]struct{//用于实现TLS功能
id int//编号
result int//返回值
}
for i:=0;
i
3、Gosched和Goexit
gosched主动让出时间片,让出时间片的时长为10ms
package main
import (
"fmt"
"runtime"
)func main(){
runtime.GOMAXPROCS(1)
exit := make(chan struct{})
go func (){//任务c
println("c")
}()
go func() {//任务a
defer close(exit)
go func(){//任务b
fmt.Println("cd")
runtime.Gosched()
fmt.Println("ab")
}()
for i := 0;
i < 4;
i++{
println("a:",i)
if i == 1 {
runtime.Gosched()//让出时间片
}
}
}()
<-exit
}
//a: 0
//a: 1
//cd
//c
//a: 2
//a: 3
goexit终止当前任务,不会影响其他并发任务,不会引发panic,不会被捕获
package mainimport "runtime"func main(){
exit := make(chan struct{})
go func(){
defer close(exit)
defer println("a")
func(){
defer func() {
println("b",recover() == nil)//执行,recover返回nil
}()
func(){
println("c")
runtime.Goexit()//停止整个堆栈调用
println("c done")//以下不会执行
}()
println("b done")
}()
println("a done")
}()
go func() {
println("ddddd")
}()
<-exit
println("main exit")
}
//c
//b true
//a
//main exit
//dddddpackage main
import (
"fmt"
"runtime"
"time"
)
func teste(){
fmt.Println("bb")
runtime.Goexit()
fmt.Println("dd")//不会执行
}
func main(){
fmt.Println("aa")
go teste()
time.Sleep(10*time.Second)
fmt.Println("cc")//会执行
}package mainimport (
"fmt"
"runtime"
)
func teste(){
fmt.Println("bb")
//runtime.Goexit()
fmt.Println("dd")//不会执行
}
func main(){
fmt.Println("aa")
go teste()
runtime.Goexit()//会等待其他任务结束,然后进程崩溃
fmt.Println("cc")
}
//aa
//bb
//dd
//fatal error: no goroutines (main called runtime.Goexit) - deadlock!
推荐阅读
- 【golang】leetcode中级-字母异位词分组&无重复字符的最长子串
- 彻底理解Golang Map
- kratos线上开源年会它来啦~
- 深入浅出 Golang 资源嵌入方案(go-bindata篇)
- 深入浅出 Golang 资源嵌入方案(前篇)
- golang 经典案例总结
- Go实战 | 基于有向无环图的并发执行流的实现
- Golang 数组和切片
- Go JSON编码与解码()
- golang map基础知识