码迷,mamicode.com
首页 > 其他好文 > 详细

go4

时间:2019-08-23 13:21:16      阅读:103      评论:0      收藏:0      [点我收藏+]

标签:print   ctf   cond   cpu核数   map   amp   后台   回收   deadlock   

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
  • 无缓冲的通道是指在接收前没有能力保存任何值的通道

技术图片

有缓冲的channel
  • 有缓冲的通道是一种在被接收前能存储一个或者多个值的通道

技术图片

放满了怎么办?

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)

go4

标签:print   ctf   cond   cpu核数   map   amp   后台   回收   deadlock   

原文地址:https://www.cnblogs.com/Doner/p/11399297.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!