go语言开发入门

go语言开发入门

每一个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)
}

选择 ifswitch函数

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)
                }
            }
        }
    }
}

数据(array)与切片(slice)

数组声明: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)

Channel

  • 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) //带缓冲

Goroutine

关键字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

  • M:表明真正的内核OS线程,真正干活的人
  • G:表明一个goroutine,它有本身的栈,instruction pointer和其余信息(正在等待的channel等等),用于调度。
  • 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执行。

其余

  • defer语句:调用一个被 defer 的函数时在函数刚要返回以前延迟执行
  • panic/recover 异常处理语句

缺陷

  • 编译生成的可执行文件尺寸很是大
  • 代码可读性差(x,y,z int, a []*struct)
  • go的滥用致使不可预见bug(注goroutine的使用应该是保守型的)

有两种思惟逻辑会想到使用goroutine

  • 业务逻辑须要并发

好比一个服务器,接收请求,阻塞式的方法是一个请求处理完成后,才开始第二个请求的处理。其实在设计的时候咱们必定不会这么作,咱们会在一开始就已经想到使用并发来处理这个场景,每一个请求启动一个goroutine为它服务,这样就达到了并行的效果。这种goroutine直接按照思惟的逻辑来使用goroutine

  • 性能优化须要并发

一个场景是这样:须要给一批用户发送消息,正常逻辑会使用

for _, user := range users {
    sendMessage(user)

}
//可是在考虑到性能问题的时候,咱们就不会这样作,若是users的个数很大,好比有1000万个用户?咱们就不必将1000万个用户放在一个routine中运行处理,考虑将1000万用户分红1000份,    //每份开一个goroutine,一个goroutine分发1万个用户,这样在效率上会提高不少。这种是性能优化上对goroutine的需求

实例httpmq

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

相关文章
相关标签/搜索