golang---知识点总结1

前言

我就不展开说要写什么了,最近在研读论文中的代码,其中很多知识都是没有接触过的,就边看边学,最近积累了一些知识点,现在我把它总结一些,主要涉及的是golang。

go init 函数

此函数是用来进行初始化工作的,在程序开始执行时按照声明的顺序被自动调用,比如说一些变量需要初始化,则可以采用这种方式,举一个在源码中的例子:

var profile string
var tls_eval bool
var split_to_buckets uint

func init() {
	flag.StringVar(&profile, "profile", "", "Should open pprof on ip:port")
	flag.BoolVar(&tls_eval, "tls-eval", false, "Split according to .timestamp and filter data")
	flag.UintVar(&split_to_buckets, "buckets", 0, "Split data to the given amount of buckets")
	flag.Parse()
}

这里的init函数就对其上面声明的变量进行了初始化,可能有的朋友看不懂函数中的内容,在这里做简单说明:

flag包是用来解析命令行参数的,类似于os.argv

  • flag.StringVar
    定义了一个指定名字、默认值和用法说明的string标签。
    usage./gofilename -参数名 xxx(代表要输入的内容)

以此类推,flag.xxxVar,都代表一个意思,将该变量绑定到输入的内容上,该内容的类型决定了xxx的类型。

  • flag.parse()
    这个函数必须调用,不然无法解析键入的参数

map

map时golang中的一个无序的键值对的集合,是通过哈希表来实现的。

  • map中的元素不是一个变量,因此不能对map的元素进行取地址操作

  • 遍历的方法:

for k,v := mapexample{
	k:是键
	v:是值
}
  • 声明
mapexample := make(map[string]int)

在这里我还想说一点,在源码中碰到的:

var parsed_json map[string]interface{}
//反序列化成map
if json.Unmarshal([]byte(json_line), &parsed_json) != nil {
	log.Printf("Failed parsing line to json object, affected line:\n%s\n", json_line)
	break
}
//然后再取map中的元素
comsys_tool, ok := parsed_json["comsys-tool"].(string)
	if !ok {
			log.Printf("No comsys-tool in json object")
			break
	}

这时会返回两个值一个是key键对应的value值,还有一个标志位(truefalse),在查询的时候和遍历的时候是不同的。

goroutine and channel

goroutine

这两个我觉得是比较golang中比较神秘的地方了,也是独有的地方,体现出了golang的高性能,除此之外,接口应该也算一个,这里都不说它了,主要说一下这两个东东。

按我的理解,我觉得学习这两者,要了解操作系统这门知识点,当然如果没学过当然也可以理解,因为没有涉及太深的理论知识。

goroutine是golang独有的东西,我们可以叫它协程,可能大家都听过进程,学过操作系统的还知道线程,但是协程是真的没有听过。

进程就是你电脑后台正在运行的程序嘛,你可以使用Ctrl + Alt + delete,打开任务管理器查看。而线程是进程的一个执行实例,一个进程可以包含多个线程从而执行不同的任务。并且我们需要知道:

  • 并发=》单核多任务,在一个时间点上,其实只有一个任务在执行
  • 并行=》多核多任务,在一个时间点上,有多个任务同时执行

现在一般的电脑都是多核的,也就是具有多个cpu,在golang中可以使用runtime包进行查看:

package main

import (
	"fmt"
	"runtime"
)

func main(){
	cpuNum := runtime.NumCPU()
	fmt.Println("cpuNum=",cpuNum)

	//设置使用多少cpu
	runtime.GOMAXPROCS(cpuNum - 1)
}

了解了这些,我们就清楚了好大一部分知识点了,离成功就不远了。。。

golang中的协程就是线程上面的分支,是轻量级的线程,可以同时多协程,开启的语句:go function_name

go协程的特点:

  • 有独立的栈空间
  • 共享程序堆空间
  • 调度由用户控制
  • 协程是轻量级线程

各一个具体例子:

import (
	"fmt"
	"strconv"
	"time"
)

func test(){
	for i := 1; i <= 10; i++{
		fmt.Println("hello world!" + strconv.Itoa(i))
		time.Sleep(time.Second) //每隔一秒
	}
}

func main(){

	go test() //开启协程
	for i := 1; i <= 100; i++{
		fmt.Println("main hello world!" + strconv.Itoa(i))
		time.Sleep(time.Second) //每隔一秒
	}
}

这样有一个问题就是无法兼顾协程和主线程的运行时间,因为协程是跟随主线程的,如果主线程执行完毕,那么协程将自动关闭。可以通过time.Sleep来兼容,但是精度不够。

package main

import (
	"fmt"
	"sync"
	"time"
)

var (
	mymap = make(map[int]int, 10)

	lock sync.Mutex // 全局互斥锁
)

func test(n int){
	res := 1
	for i :=1; i <= n; i++{
		res *= i
	}

	//加锁
	lock.Lock()

	mymap[n] = res

	//解锁
	lock.Unlock()
}

func main(){
	//设置多个协程计算阶乘
	for i:=1;i<=20;i++{
		go test(i)
	}
	time.Sleep(time.Second*5)
	lock.Lock()
	for i, v := range mymap{
		fmt.Printf("map[%d]=%d\n",i,v)
	}

	lock.Unlock()


}

多个协程同时开启,对于test函数的使用发生了阻塞,所以这里提供了一个解决办法,通过lock sync.Mutex 全局互斥锁,来对test以及map互斥使用,这样我们就可以顺利运行了。

channel

利用channel可以解决协程之间的通信问题,下面简单介绍:

  • 初始化:
1var intChan chan int
   intChan = make(chan int,3)

2、intChan := make(chan int,3)
  • 本质
    队列,FIFO,先进先出,就类似于是一个管道。

  • 遍历

for v := range intChan{}
//channel没有索引,所以只有返回值,而无下标
  • 写入,写出
//写入
intChan<-10

//写出
value :=<- intChan

另外提一下代码中的一个知识点:

func line_from_stdin(stdin_chan chan<- string) {}

表明channel是单向的,只能用来接受数据。

将协程放到管道,多个协程操作同一个管道时不会发生资源竞争问题,就是因为channel的特性。

在这里插入图片描述

给一个实际例子:

package main

import "fmt"

func main(){
	var intChan chan int

	//存放三个int类型的管道
	intChan = make(chan int,3)

	fmt.Printf("intChan 的值=%d\n",intChan) //存放管道的地址

	//向管道写入数据
	intChan<- 10
	num := 211
	intChan<- num



	intChan<-50

	fmt.Printf("channel len=%v, cap=%v \n",len(intChan),cap(intChan))

	//不能超出cap


	//从管道中读取数据

	var num2 int
	num2 = <-intChan
	fmt.Println("num2=",num2)

	fmt.Printf("channel len=%v, cap=%v \n",len(intChan),cap(intChan))

	//在没有使用协程的情况下,如果我们的管道数据已经全部取出,再取就会报错 deadlock

	num3 := <-intChan
	num4 := <-intChan

	fmt.Println("num3,num4=",num3,num4)

	fmt.Printf("channel len=%v, cap=%v \n",len(intChan),cap(intChan))
}

select

用法:主要用于监听和channel有关的I/O操作,当I/O操作发生时,触发相应的动作:

  • 当管道读到数据时:case <- chan:
  • 当管道写入数据时:case chan <- 10
  • default

Json序列化和反序列化

定义:
Json序列化,是将有key-value结构的数据类型(结构体、map、slice)序列化成Json字符串的操作,反序列化相反。

主要通过encoding/json包实现,里面包含:

  • Marshal
    返回值:byte,error
  • Unmarshal
    返回值:error

两个包用于序列化和反序列化。

结构体序列化的别称:

先给个例子:

type Monster1 struct {
	Name string `json:"monster_name"`
	Age int	`json:"monster_age"`
	Birthday string `json:"monster_birthday"`
	Sal float64 `json:"monster_sal"`
	Skill string `json:"monster_skill"`
}

比如这个结构体序列化的时候会使用其后面的别称。

反序列化时,输入有两个部分:

  • str反序列化的字符串,需要转化为byte[]byte(str)
  • 第二个输入是要转成的类型的引用,比如:&monster

map中的value为interface

mapint := make(map[string]interface{})

interface{}代表任何类型,如果要转换类型,则采用:a.(string)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值