每一个Go程序包含一个名为main的包以及其main函数,在初始化后,程序从main开始执行,避免引入不使用的包(编译不经过)编程
基本数据类型数组
bool, byte int,int8,int16,int32,int64 uint8,uint16,uint32,uint64 float32,float64(没有float类型) string
变量赋值性能优化
var a a = 12 a := 12 a,b :=12,23
常量赋值服务器
const( a = iota b )
循环只有 for并发
for i:=0;i<10;i++{ do Something... } for{ //至关于while(true){} } for _,v:= range list{ //range用法返回list数组或者列表的k,v两个值(k数组索引从0开始,v值) fmt.Print("%s", v) }
选择 if 和 switch函数
a := 1 b := 1 if a+b > 2 { // 注:if(条件不带括号,且左大括号与if保持同行) }
完整demo 大白加大白等于白胖胖.求大,白,胖各是数字多少?性能
package main import ( "fmt" "strconv" ) /* 大白加大白等于白胖胖.求大,白,胖各是数字多少? */ func main() { for d := 1; d < 10; d++ { for b := 1; b < 10; b++ { for p := 1; p < 10; p++ { daBai, _ := strconv.Atoi(strconv.Itoa(d) + strconv.Itoa(b)) // fmt.Println("大白", daBai) baiPangPang, _ := strconv.Atoi(strconv.Itoa(b) + strconv.Itoa(p) + strconv.Itoa(p)) // fmt.Println("白胖胖", baiPangPang) if daBai+daBai == baiPangPang { fmt.Println("-------------------大 白 胖--------------------") fmt.Printf("大 = %d, 白 = %d, 胖 = %d\n", d, b, p) fmt.Println("白胖胖: ", baiPangPang) } } } } }
数组声明:ArrayType = "[" ArrayLength "]" ElementType .学习
var a [32] int var b [3][5] int
(1)数组是值类型。将一个数组赋值给另外一个,会拷贝全部的元素.优化
(2) 若是你给函数传递一个数组,其将收到一个数组的拷贝,而不是它的指针.ui
(3)数组的大小是其类型的一部分,类型[10]int和[20]int是不一样的。数组长度在声明后,就不可更改.
切片声明:SliceType = "[" "]" ElementType .
var a []int
(1)没有初始化的slice为nil.
(2)切片(slice)对数组进行封装,实际上,切片能够当作大小能够动态变化的数组.
(3)Go中大多数的数组编程都是经过切片完成,而不是简单数组.
通常来讲,有两种方式来初始化切片:
//经过数组方式 var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} var mySlice []int = myArray[:5] //make方式 make([]T, length, capacity)
Goroutine和channel是Go在“并发”方面两个核心feature。
Channel是goroutine之间进行通讯的一种方式,go所提倡的"应该以通讯做为手段来共享内存"的最直接体现。
Channel声明:
ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) ElementType .
var ch chan int
var ch1 chan<- int //ch1只能写
var ch2 <-chan int //ch2只能读
//make初始化
putnamechan := make(chan string, 100) //带缓冲
关键字go,启用Goroutine的惟一途径
//同时向五我的打招呼 func main(){ names := []string{"Eric","Tom","Jack","Jim"} for _,name:= range names{ go func(){ fmt.Printf("Hello,%s.\n",name) }() } runtime.Gosched() }
Go的调度器内部有三个重要的结构:M,P,S
P:表明调度的上下文,能够把它看作一个局部的调度器,使go代码在一个线程上跑,它是实现从N:1到N:M映射的关键。
图中看,有2个物理线程M,每个M都拥有一个context(P),每个也都有一个正在运行的goroutine。
P的数量能够经过GOMAXPROCS()来设置,它其实也就表明了真正的并发度,即有多少个goroutine能够同时运行。
图中灰色的那些goroutine并无运行,而是出于ready的就绪态,正在等待被调度。P维护着这个队列(称之为runqueue),
Go语言里,启动一个goroutine很容易:go function 就行,因此每有一个go语句被执行,runqueue队列就在其末尾加入一个
goroutine,在下一个调度点,就从runqueue中取出一个goroutine执行。
好比一个服务器,接收请求,阻塞式的方法是一个请求处理完成后,才开始第二个请求的处理。其实在设计的时候咱们必定不会这么作,咱们会在一开始就已经想到使用并发来处理这个场景,每一个请求启动一个goroutine为它服务,这样就达到了并行的效果。这种goroutine直接按照思惟的逻辑来使用goroutine
一个场景是这样:须要给一批用户发送消息,正常逻辑会使用
for _, user := range users { sendMessage(user) } //可是在考虑到性能问题的时候,咱们就不会这样作,若是users的个数很大,好比有1000万个用户?咱们就不必将1000万个用户放在一个routine中运行处理,考虑将1000万用户分红1000份, //每份开一个goroutine,一个goroutine分发1万个用户,这样在效率上会提高不少。这种是性能优化上对goroutine的需求
http协议实现的消息队列,数据持久化levelDb
//httpmq mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { } //net/http包起路由作拦截处理(put,get,status,view) //接收name\data参数 //起四个channel putnamechan := make(chan string, 100) //入队name管道 putposchan := make(chan string, 100) //入队数据索引管道 getnamechan := make(chan string, 100) //出队name管道 getposchan := make(chan string, 100) //出队数据索引管道 //两个Goroutine作消息管道流入队出队操做 go func(chan string, chan string) { for { name := <-putnamechan // putpos := httpmq_now_putpos(name) putposchan <- putpos } }(putnamechan, putposchan) go func(chan string, chan string) { for { name := <-getnamechan getpos := httpmq_now_getpos(name) getposchan <- getpos } }(getnamechan, getposchan) //put入队操做 putnamechan <- name putpos := <-putposchan queue_name := name + putpos if data != "" { db.Put([]byte(queue_name), []byte(data), nil) } else if len(buf) > 0 { db.Put([]byte(queue_name), buf, nil) } //get出队操做 getnamechan <- name getpos := <-getposchan if getpos == "0" { w.Write([]byte("HTTPMQ_GET_END")) } else { queue_name := name + getpos v, err := db.Get([]byte(queue_name), nil) if err == nil { w.Header().Set("Pos", getpos) w.Write(v) } else { w.Write([]byte("HTTPMQ_GET_ERROR")) } }
put操做
name --> putnameChannel --> 生成putPos --> putposChannel --> name+pos生成key持久化data
get操做
name --> getnameChannel --> 生成getPos --> getposChannel --> name+pos生成key getData