go4
go4
引用循环
package main
const N=3
func main(){
m := make(map[int]*int)
for i:=0 ; i<N;i++{
m[i]=&i
}
for _,v:= range m{
print(*v)
}
}
0 = 0 -> 2
1 = 1 -> 2
2 = 2 -> 2
0 = 0 -> 3
1 = 1 -> 3
2 = 2 -> 3
----> 333
最后没i++ 了,就等于3了 0x123
正常输出
package main
const N=3
func main(){
m := make(map[int]int)
for i:=0 ; i<N;i++{
m[i]=i
}
for _,v:= range m{
print(v)
}
}
--->012
make() new()
make() 创建切片,map,数组,通道
new() 创建自定义对象
make()会初始化,new()不会
锁,for抛协程和函数正常传值
const M = 10
func main(){
m := make(map[int]int)
wg := &sync.WaitGroup{}
mu := &sync.Mutex{}
wg.Add(M)
for i:=0 ; i< M;i++{
//go func(){ //go 抛协程 for 生成不同的新值
go func(i int){ // 正常 10
defer wg.Done()
mu.Lock()
m[i] = i
mu.Unlock()
}(i)
}
wg.Wait()
println(len(m))
}
//1或者10
go的加载顺序
main包-->const常量--->var变量--->init()--->main函数
协程写入必须加锁
const M1 = 10
func main(){
m1 := make(map[int]int)
wg1:= &sync.WaitGroup{}
//flag := &sync.Mutex{}
wg1.Add(M1)
for i:=0 ; i< M1;i++{
go func(){
defer wg1.Done()
//flag.Lock()
m1[rand.Int()] = rand.Int()
//flag.Unlock()
}()
}
wg1.Wait()
println(len(m1))
}
取地址和取值
type S struct {
a,b,c string
}
func main(){
x := interface{}(&S{"a","b","c"})
y := interface{}(&S{"a","b","c"})
fmt.Println(x==y)
x1 := interface{}(S{"a","b","c"})
y1 := interface{}(S{"a","b","c"})
fmt.Println(x1==y1)
}
--->
false
true
map中结构体
json反格式化到结构体小写取不到
栈和堆的区别
区别:
栈:空间比较小 , 存储变量/函数参数等,编译器自动分配和释放
堆:空间比较大, 一般有程序员分配和释放(java和Python垃圾回收自动处理,c需要处理内存) 存储数据
分配栈上 : a := xx var b = .. //前面放栈后面放堆
分配堆上 : new()大多数情况分配到堆上
反射
type User struct {
Id int
Name string
Addr string
}
func (u User)Hello(){
fmt.Println("hello")
}
//反射操作
func Info(o interface{}){ //获取类型信息
t := reflect.TypeOf(o)
fmt.Println("类型是:",t.Name()) //封装的直接返回类型
//获取值
v := reflect.ValueOf(o)
fmt.Println("值是:",v)
// 获取对象字段信息
fmt.Println()
//t.NumField() 获取字段的数量,决定循环次数
for i:= 0; i<t.NumField();i++ {
// 通过索引,取每个字段
f := t.Field(i)
// Interface() : 可以去到字段对应的值
val := v.Field(i).Interface()
fmt.Printf("%s:%v = %v \n",f.Name,f.Type,val)
}
//获取方法
fmt.Println()
for i:= 0 ; i< t.NumField();i++{
m := t.Field(i)
fmt.Printf("%s:%v\n",m.Name,m.Type)
}
}
func main(){
u:=User{1,"zs","bj"}
Info(u)
}
--->
类型是: User
值是: {1 zs bj}
Id:int = 1
Name:string = zs
Addr:string = bj
Id:int
Name:string
Addr:string
Hello:func(main.User)
反射获得匿名变量
type User struct {
Id int
Name string
Addr string
}
type Boy struct {
User
Hobby string
}
func (u User)Hello(){
fmt.Println("hello")
}
func main(){
u:=Boy{User{1,"zs","bj"},"aa"}
t:= reflect.TypeOf(u)
// Anonymous 是true,则是匿名字段
// %#:获取详细信息
fmt.Printf("%#v\n",t.Field(0))
// 获取值
v := reflect.ValueOf(u)
fmt.Printf("%#v\n",v.Field(0))
}
// 反射获得匿名变量
//reflect.StructField{Name:"User", PkgPath:"", Type:(*reflect.rtype)(0x4b8160), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}
//main.User{Id:1, Name:"zs", Addr:"bj"}
反射修改值
func main(){
abc := 123
//abc = 222 // 编码时修改
v := reflect.ValueOf(&abc)
v.Elem().SetInt(3432) // api
fmt.Println("abc",abc) // abc 3432 运行时修改
}
修改结构体
// 反射操作修改一个结构体的值
func setValue(o interface{}){
v := reflect.ValueOf(o)
// 获取指针指向的真正的元素
v = v.Elem()
f := v.FieldByName("Id")
// Kind() 可以判断类型
if f.Kind() == reflect.Int{
f.SetInt(222)
}
}
func main(){
u:= User1{1,"z","bj"}
setValue(&u)
fmt.Println(u)
}
--->{222 z bj}
函数对象的修改
func (u User1) Hello(){
fmt.Println("hello")
}
//func (u User1) Hello(name string){
// fmt.Println("hello",name)
//}
func main(){
u:= User1{1,"z","bj"}
v := reflect.ValueOf(u)
m := v.MethodByName("Hello")
args := []reflect.Value{}
//args := []reflect.Value{11} // 带参数的
//m.Call(args) //直接调用 hello
m.Call(args)
}
并发与并行
java的并发也不好,老语言
c语言 并发好 , go 稍微差一点,天然支持高并发,不用代码层次
处理高并发
没有高并行:加机器
老公司,懒得转语言了,即使不快
新公司,都是go
goroutine
- go并发设计的核心
- 是协程
创建
go + 语句
func newTask(){
i:= 0
for {
i++
fmt.Printf("newTask i=%d \n",i)
time.Sleep(1*time.Second)
}
}
func main(){
go newTask()
i:= 0
for {
i++
fmt.Printf("mainTask i=%d \n",i)
time.Sleep(1*time.Second)
}
}
--->
//mainTask i=1
//newTask i=1
//mainTask i=2
//newTask i=2
//newTask i=3
//mainTask i=3
同时跑,主协程结束了,子协程还没跑到
解决:
// 阻塞, 睡眠 锁 解决
for{}
runtime包
runtime.Gosched()
runtime.Goexit()
runtime.GOMAXPROCS()
runtime.Gosched()
func newTask(){
i:= 0
for {
i++
fmt.Printf("newTask i=%d \n",i)
time.Sleep(1*time.Second)
}
}
func main(){
go newTask()
//go newTask()
//i:= 0
//for {
// i++
// fmt.Printf("mainTask i=%d \n",i)
// time.Sleep(1*time.Second)
//}
// 阻塞, 睡眠 锁 解决
for{}
}
//mainTask i=1
//newTask i=1
//mainTask i=2
//newTask i=2
//newTask i=3
//mainTask i=3
runtime.Goexit()
func main() {
go func() {
defer fmt.Println("A.defer")
// 匿名函数
func(){
defer fmt.Println("B.defer")
// 结束当前协程
runtime.Goexit() //B.defer A.defer 不走之后的了,然后最后延时
fmt.Println("B")
}()
fmt.Println("A")
}()
for{}
}
// 不退出版
//B
//B.defer
//A
//A.defer
runtime.GOMAXPROCS()
func main() {
// 并行计算CPU核数
runtime.GOMAXPROCS(1) //11111111111111111111111111111
//runtime.GOMAXPROCS(3) //011001100110011100011001100110
for {
go fmt.Print(0)
fmt.Print(1)
}
}
channel 管道
传数据
-
channel可以用内置make()函数创建
-
定义一个channel时,也需要定义发送到channel的值的类型
make(**chan** 类型)
make(**chan** 类型, 容量)
-
当 capacity= 0 时,channel 是无缓冲阻塞读写的,当capacity> 0 时,channel 有缓冲、是非阻塞的,直到写满 capacity个元素才阻塞写入
-
channel通过操作符<-来接收和发送数据,发送和接收数据语法:
channel <- value // 发送vlaue到channel
<-channel // 从channel取数据,并丢弃
x := <-channel // 从channel取数据,并赋值给x
x, ok := <-channel // 功能同上,检查通道是否关闭,是否为空
代码
func main(){
// 创建管道
c := make(chan int) // 只能传int的
// 子协程存入数据到管道
go func(){
defer fmt.Println("111")
fmt.Println("222")
// 向管道发送数据
c <- 123
}()
// 主协程从管道取数据
num := <-c
fmt.Println("num = ",num)
fmt.Println("over")
}
//222
//111
//num = 123
//over
无缓冲的channel
- 无缓冲的通道是指在接收前没有能力保存任何值的通道
![2018-01-15_135129](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image002.png)
有缓冲的channel
- 有缓冲的通道是一种在被接收前能存储一个或者多个值的通道
![2018-01-15_150701](file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image002.png)
放满了怎么办?
func main(){
// 无缓冲通道
//c := make(chan int, 0) //
// 有缓冲通道
c := make(chan int, 3) // 缓冲3个
fmt.Printf("len(c)=%d,cap(c)=%d\n",len(c),cap(c))
// 模拟两个人 子协程 存数据
go func() {
for i:=0 ; i<3 ; i++{
c <- i
fmt.Printf("子协程[%d]运行,len(c)=%d,cap(c)=%d\n",i,len(c),cap(c))
}
}()
// 主协程 取数据
time.Sleep(2*time.Second) // 睡,没有接数据,有接就发了
for i:=0 ; i<3 ; i++{
num := <- c
fmt.Println("num=",num)
}
}
//len(c)=0,cap(c)=0 //在这里等待
//num= 0
//子协程[0]运行,len(c)=0,cap(c)=0
//子协程[1]运行,len(c)=0,cap(c)=0
//num= 1
//num= 2
//有缓冲
//len(c)=0,cap(c)=3
//子协程[0]运行,len(c)=1,cap(c)=3
//子协程[1]运行,len(c)=2,cap(c)=3
//子协程[2]运行,len(c)=3,cap(c)=3
// 延时了 ,再接了
//num= 0
//num= 1
//num= 2
如果缓冲设置小了,那么缓冲小的,就是有缓冲,
其他的是走无缓冲,先走主协程,等待等等
通道里数据少了,取多的,报错了
func main(){
c := make(chan int, 3) // 缓冲3个
fmt.Printf("len(c)=%d,cap(c)=%d\n",len(c),cap(c))
go func() {
for i:=0 ; i<10 ; i++{
c <- i
fmt.Printf("子协程[%d]运行,len(c)=%d,cap(c)=%d\n",i,len(c),cap(c))
}
}()
// 主协程 取数据
for {
if val,ok := <- c;ok{
fmt.Println(val)
}else{
break
}
}
fmt.Println("结束了")
}
---->错误显示
///...
//7
//8
//9
//fatal error: all goroutines are asleep - deadlock!
// goroutine 1 [chan receive]:
go func() {
for i:=0 ; i<10 ; i++{
c <- i
fmt.Printf("子协程[%d]运行,len(c)=%d,cap(c)=%d\n",i,len(c),cap(c))
}
close(c) //标识一下,没有了
}()
---> 关闭一下,就可以了
单方向的channel
var ch1 chan int // 双向的
var ch2 chan<- float64 单向通道,只用于存入数据,只写float64
var ch3 <-chan int //取数据
func main(){
//通道
c := make(chan int ,5)
//转换为只写的通道
var send chan <- int = c
//转换为只读的通道
var recv <- chan int = c
send <- 123
fmt.Println("<-recv",<-recv)
// <-recv 123
}
生产者和消费者模型(和后台的关系)
// 创建生产者
func producter(out chan<-int ) {
defer close(out)
// 可以改数据
for i:= 0; i<5;i++{
out <-i
}
}
// 创建消费者
func consumer(in <-chan int) {
// 用于查找东西 无法改数据,迭代的是range
for x:= range in {
fmt.Println(x)
}
}
func main() {
c:=make(chan int,10)
go producter(c)
consumer(c)
for {}
}
//0
//1
//2
//3
//4
定时器
Timer : 时间到了,就执行,执行一次
Ticker : 时间到了,就执行,执行多次
func main() {
time1 := time.NewTimer(time.Second*2)
//打印当前时间
fmt.Printf("当前时间:%v\n",time.Now())
fmt.Printf("timer里的时间:%v\n",<-time1.C)
}
//当前时间:2019-08-23 12:27:13.7582115 +0800 CST m=+0.002000201
//timer里的时间:2019-08-23 12:27:15.7683264 +0800 CST m=+2.012115101
2. 只执行一次
time2:=time.NewTimer(time.Second*1)
for{
//<-time2.C
c:=<-time2.C
//fmt.Println("xxx")
fmt.Println(c)
}
fatal error: all goroutines are asleep - deadlock!
2019-08-23 12:29:45.3538822 +0800 CST m=+1.002057301
goroutine 1 [chan receive]:
main.main()
//3.停止定时器
time3:=time.NewTimer(time.Second*2)
go func() {
<-time3.C
fmt.Println("时间到")
}()
stop:=time3.Stop()
if stop{fmt.Println("3已关闭")}
//3已关闭
time4:=time.NewTimer(time.Second*2)
time4.Reset(3*time.Second)
fmt.Println(<-time4.C)