golang学习笔记

golang admin 99℃ 0评论

起因:

最近投了个腾讯面试,长沙腾讯云,电话面比较紧张,好在面试官给了个机会,今天4.27,5月5日前给一个类似apache ab的程序,用golang实现

 

先做个计划吧:

时间10天左右,上班的这几天入门golang基础,进阶实战假期中实现

  1. 认知,语法, 27 28
  2. 小demo 29
  3. 整体回顾,why? 30
  4. 初步实现 5.1
  5. 查看开源项目 5.2
  6. 修改总结5.3
  7. 深入及网上做题 5.4
  8. 了解更多知识点 5.5

因为以前有接触过golang(从入门到放弃),所以安装编译这些这里不作记录

 

语法:

  1. 基本类型
    1. 数值型:整数(int8, int16, int 32, int64),小数(float32, float64),复数(complex64, complex128)
    2. 布尔型,默认false
    3. 字符串型,默认“”
  2. 定义与赋值
    1. 全局变量var, 局部变量可省var,用:来替代
    2. 示例
      //普通变量
      var a=32
      var a int=64
      a:=128
      a:=int(256)
      //常量
      const name string = "damimi"
      const sex = "girl"
      //常量复合定义
      const a, b = 1, 2
      const ( 
          a = 1
          b = 2
      )
      //特殊定义, 这里
      const (
          a, b = iota, iota*2
          c, d
          _=iota
          e=iota
      )

       

  3. 加载顺序
    1. 程序入口为main()方法,且必须为package main;
    2. 多个没有父子依赖关系的文件,按照字母顺序加载
    3. 有依赖关系的文件,先加载父文件,再加载子文件。在加载时会读取init()方法(如果有的话)
    4. 多次导入,只算一次
    5. 以下划线_为别名的import, 只加载init()方法,其它方法都忽略掉;
    6. 加载的文件可以定义别名,在运算时,以别名为准,相同的才可以计算
    7. 文件夹不必和package相同,但一个文件夹下的package必须相同
    8. go 不解决循环依赖的问题
  4. 切片与数组区别(直接代码)
    package main
    
    import "fmt"
    //import "reflect"
    //import "unsafe"
    
    func main() {
    	//数组与切片对比
    	var a1 [5]int
    	a2 := [...]int{1, 2, 3, 4}
    
    	fmt.Println(a1, a2)
    
    	a3 := [...]int{2: 2, 4: 4}
    	fmt.Println(a3)
    
    	a4 := [5]int{2: 2, 4: 4}
    	fmt.Println(a4)
    
    	var b1 []int
    	fmt.Println(b1)
    
    	b1 = make([]int, 5, 5+3)
    	fmt.Println(b1)
    	fmt.Printf("b1=%v, len=%d, cap=%d\n", b1, len(b1), cap(b1))
    
    	b2 := make([]int, 3, 5)
    	fmt.Printf("b2=%v, len=%d, cap=%d\n", b2, len(b2), cap(b2))
    
    	/*
    	var a = [] int{1,2,3,4,5}
    	fmt.Println(a)
    
    	b := make([]int, 0)
    	fmt.Println(b)
    
    	a[1] = 10
    
    	fmt.Println(b)
    
    	c := a[0:3]
    	fmt.Println(c)
    	*/
    	//i := 33.0
    	//fmt.Println(reflect.TypeOf(i))
    	//fmt.Println(unsafe.TypeOf(i))
    
    }

    总结,运行一看便知,数组大小固定,切片相当于动态数组,大小可定义

  5. 协程(语法中的硬核部分)
    package main
    
    import "fmt"
    import "time"
    
    
    func say(s string){
    	for i := 0; i < 5; i++ {
    		fmt.Println(s)
    		time.Sleep(time.Second*1) 
    	}
    }
    
    func main() {
    
    	go say("hello")
    	go say("world")
    
    	time.Sleep(time.Second*6) 
    }

    以上是两个任务同时执行

    package main
    
    import "fmt"
    import "sync"
    
    var wg sync.WaitGroup
    
    func say(s string){
    	for i := 0; i < 5; i++ {
    		fmt.Println(s)
    	}
    	wg.Done()
    }
    
    func main() {
    	wg.Add(2)
    
    	go say("hello")
    	go say("world")
    
    	wg.Wait()
    }

    以上是专业的任务同步进行,比如查两个库,同时查,如果每个查询要1秒,并发查就只要1秒就能搞定

    package main
    
    import (
        "strconv"
        "fmt"
        "time"
    )
    
    func main() {
        ch1 := make(chan int)
        ch2 := make(chan string)
        go pump1(ch1)
        go pump2(ch2)
        go suck(ch1, ch2)
        time.Sleep(time.Duration(time.Second*30))
    }
    
    func pump1(ch chan int) {
        for i := 0; ; i++ {
            ch <- i * 2
            time.Sleep(time.Duration(time.Second))
        }
    }
    
    func pump2(ch chan string) {
        for i := 0; ; i++ {
            ch <- strconv.Itoa(i+5)
            time.Sleep(time.Duration(time.Second))
        }
    }
    
    func suck(ch1 chan int, ch2 chan string) {
        chRate := time.Tick(time.Duration(time.Second*5)) // 定时器
        for {
            select {
            case v := <-ch1:
                fmt.Printf("Received on channel 1: %d\n", v)
            case v := <-ch2:
                fmt.Printf("Received on channel 2: %s\n", v)
            case <-chRate:
                fmt.Printf("Log log...\n")
            }
        }
    }
    

    这个网上找的demo,有点困了,通过通道, 实现了对两个协程的数据收集,这就该就是协程之间的通信了

  6. 这里中间需要省略一部分内容,后面有时间再补充,五一假期回家了,每天抽部分时间看代码,主要是了解一些语法上的关键点和看示例代码,我觉得go语言层面比较难的就是多线程,通道,语法上其实说到底也没有多大难度,关键是后面对一些基础库,常用库的理解,对操作系统的理解,网络知识的理解,应用中对一此中间件的理解,对开源库的搜索及应用,最后,对于项目,可能更多的是考验综合能力
  7. 最后放一个简单版本的程序代码
    package main
     
    import (
        "fmt"
        "flag"
        "net/http"
        "sync"
        "time"
    )
    
    var (
     n int
     c int
     url string
    )
    
    func init() {
     flag.IntVar(&c, "c", 10, "pre secend request")
     flag.IntVar(&n, "n", 2, "total request")
     flag.StringVar(&url, "url", "localhost", "request url")
    }
    
    var wg sync.WaitGroup
     
    func run(num int) {
     defer wg.Done()
     
     for i := 0; i < num; i++ {
      resp, _ := http.Get(url)
      defer resp.Body.Close()
     }
    }
     
    func main() {
     
     start_time := time.Now().UnixNano()
     
     flag.Parse()
     
     fmt.Println("c:", c, " n:", n, " url:", url)
    
     total := c*n
     
     for i := 0; i < c; i++ {
      wg.Add(1)
      go run(n)
     }
     
     wg.Wait()
     end_time := time.Now().UnixNano()
     cost := float64(end_time-start_time)/1e9
     
     fmt.Println("Total:", total)
     fmt.Println("UseTime:", fmt.Sprintf("%.4f", cost), "s")
     fmt.Println("Request Pre Second:", fmt.Sprintf("%.2f", float64(total)/cost))
    }

    这里主要用到flag库,用来处理命令行参数,提代帮助选项;用到net/http库用来获取网页数据,相当于模拟请求;接下来就是多线程(go runtime)这个比一般的线程更加轻量级,最后还需sync库来进行线程管理,没这个,主线程会直接停止,导致子线程异常退出,导致最终出来的结果肯定是有问题的。

 

 

 

转载请注明:朋克网 » golang学习笔记

喜欢 (1)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址