zoukankan      html  css  js  c++  java
  • 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

    1566524831850

    最后没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 
    ",f.Name,f.Type,val)
    
    
    	}
    	//获取方法
    	fmt.Println()
    	for i:= 0 ; i< t.NumField();i++{
    		m := t.Field(i)
    		fmt.Printf("%s:%v
    ",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
    ",t.Field(0))
    
       //  获取值
       v := reflect.ValueOf(u)
       fmt.Printf("%#v
    ",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 
    ",i)
    		time.Sleep(1*time.Second)
    	}
    }
    func main(){
    	go newTask()
    
    
    	i:= 0
    	for {
    		i++
    		fmt.Printf("mainTask i=%d 
    ",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 
    ",i)
          time.Sleep(1*time.Second)
       }
    }
    func main(){
       go newTask()
       //go newTask()
    
       //i:= 0
       //for {
       // i++
       // fmt.Printf("mainTask i=%d 
    ",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 管道

    1566531335865

    传数据

    • 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
    ",len(c),cap(c))
    	// 模拟两个人  子协程  存数据
    	go func() {
    		for i:=0 ; i<3 ; i++{
    			c <- i
    			fmt.Printf("子协程[%d]运行,len(c)=%d,cap(c)=%d
    ",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
    ",len(c),cap(c))
    	go func() {
    		for i:=0 ; i<10 ; i++{
    			c <- i
    			fmt.Printf("子协程[%d]运行,len(c)=%d,cap(c)=%d
    ",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
    ",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
    ",time.Now())
    
    	fmt.Printf("timer里的时间:%v
    ",<-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)
    
    
  • 相关阅读:
    Jquery+ajax+bootstrap
    Js+Jquery
    css(2)+JS
    css
    mysql 高级
    Git
    Redis
    Nginx
    python爬虫 | 一条高效的学习路径
    拉勾网爬取全国python职位并数据分析薪资,工作经验,学历等信息
  • 原文地址:https://www.cnblogs.com/Doner/p/11399296.html
Copyright © 2011-2022 走看看