go语言第一篇

Posted 牧竹子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go语言第一篇相关的知识,希望对你有一定的参考价值。

环境搭建

  • 下载安装文件https://golang.google.cn/dl/

官方给的大陆地区链接。Windows直接下载msi文件安装,会自动设置好环境变量。

  • IDEA 安装go插件 
    打开idea,File –> settings –> plugins 
    点击 Browse repositories ,搜索 go ,列表中显示Go LANGUAGE,点击install安装

基础语法

基础教程参考

http://www.runoob.com/go/go-slice.html


go的数据类型比较少,这里就直接路略过

概述(入门级理解,如果大神有想说的直言)

数组和分片的区别 
数组是定长,而分片是可以动态扩容的,初始化的时候有无长度的限制

switch和其他语言相比可以省略break,只执行case不会像其他语言那样贯穿。

select和switch相似,单不会有根据用户的type执行相应的case而是随机执行可用的,如果没有则执行default

对象关键字使用struct而非class

没有继承

有接口概念,但是自定义类型实现接口不在类型尖括号内实现,IDE无法根据现有的接口找到已经实现了的相应自定义类型

函数的参数和返回值相比其他语言位置互换,类的方法一概写在类定义尖括号外面

使用并发中不涉及线程概念(这里仅限于入门指导上不会涉及,底层原来另说),和你想象的其他语言多线程完全不一样,初次尝试似乎就是单线程的轮询上班似的。

并发

首先并行!=并发,并发是逻辑上的并行.

goroutine

goroutine是Go语言中的轻量级线程实现.它是一个普通的函数,只需使用保留字 go 作为开头。 
例如:两个goroutine打印1-10

//这个程序是不会输出的,因为go还没执行完成,main已经退出了

func test(){    for i:=0; i<10 ;i++{        fmt.Print(i)    } } func main()  {    go test()    go test()

}

没有打印结果

为什么没有打印结果 
main使用的是主线程,而test()由于还在执行打印,main执行到最后一行时主线程关闭了,因此也不会执行打印。

解决上面的问题可以让main等待一段时间,让test执行,也可以使用信道进行通信. 
1)在main的最后加上time.Sleep(time.Second) 停顿一秒 
2)使用信道:channel,因为channel的接收方会等待接收到消息时阻塞

打印结果

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9

channel

对于channel类似于linux中的管道,在goroutine之间进行通信,信道可以分为无缓冲的和有缓冲的.对于无缓冲的放了数据就需要取出,否则阻塞;对于有缓冲的信道,可以存储对应大小的数据,满了以后就在存数据就类似于非阻塞的,但是当写入信道满了时会发生阻塞,而读出信道空了时会发生阻塞.

  • 无缓冲的信道是一批数据一个一个的「流进流出」

  • 缓冲信道则是一个一个存储,然后一起流出去

eg: ch := make(chan type, value)

使用信道

var ch = make(chan int)func test(){    for i:=0; i<10 ;i++{
        fmt.Print(i)
    }
    ch<-0}func main()  {    go test()    go test()
    <-ch
    <-ch
}

为什么是串行的结果

对于上面的例子,输出结果跟串行结果一样,why?? 
因为Go默认所有的goroutine只能在一个线程里(单核)跑.而一个goroutine不阻塞是不会把CPU让让给其他goroutine的.所以执行结果类似于串行. 
对于Go中的并行可以使用runtime包中的函数,

实际上,默认Go所有的goroutines只能在一个线程里跑,只有当一个goroutines被阻塞了才会让出CPU给其他goroutines。 
而一个goroutine并不相当于一个线程,goroutine的出现正是为了替代原来的线程概念成为最小的调度单位。(一旦运行goroutine时,先去当前线程查找,如果线程阻塞了,则被分配到空闲的线程,若无空闲线程,就新建一个线程。注意的是,当goroutine执行完毕后,线程不会被回收,而是成为了空闲的线程。) 
  如果当前goroutine不发生阻塞,它是不会让出CPU给其他goroutine的, 在上面的代码实例中,输出会是一个一个goroutine进行,而如果使用sleep函数,则阻塞掉了当前goroutine, 当前goroutine主动让其他goroutine执行, 所以形成了并发。

1、允许Go使用多核(runtime.GOMAXPROCS)

在信道的样例中 main()下面一行加上如下代码

//使用两个核
    runtime.GOMAXPROCS(2)
 
   
   
 
  • 1

  • 2

上面会抢占式输出 
在多核情况下,如果一个goroutine发生阻塞,其他goroutine会在另一个线程(核)上执行

2、手动显式调动(runtime.Gosched)

func test(){    for i:=0; i<10 ;i++{
         runtime.Gosched() // 显式地让出CPU时间给其他goroutine
        fmt.Print(i)
    }
    ch<-0

}

执行结果:

0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9

主动让出CPU时间的方式仍然是在单核里跑。但手工地切换goroutine导致了看上去的“并行”而显得不自然。

runtime

runtime包是goroutine的调度器

关于runtime包几个函数: 
Gosched() //让出cpu 
NumCPU()//返回当前系统的CPU核数量 
GOMAXPROCS() //设置最大的可同时使用的CPU核数 
Goexit() //退出当前goroutine(但是defer语句会照常执行)

总结

  默认所有goroutine会在一个原生线程里跑,也就是默认只使用一个CPU核。如果当前goroutine不发生阻塞,它是不会让出CPU时间给其他同线程的goroutines的,这是Go运行时对goroutine的调度,我们也可以使用runtime包来手工调度。 
  若我们开启多核,当一个goroutine发生阻塞,Go会自动地把与该goroutine处于同一系统线程的其他goroutines转移到另一个系统线程上去,以使这些goroutines不阻塞。从而实现并行效果。



人海茫茫孤影浮


伞如浮萍风飘雨

平平淡淡的

普通经历

一个工作多于生活的
程序员
自述
牧竹子


坐标/深圳

CSDN博客:blog.csdn.net/zjcjava/

Email:zjcjava@163.com 




以上是关于go语言第一篇的主要内容,如果未能解决你的问题,请参考以下文章

Go-第一篇

go语言第一篇。九大优势和3个缺点。

[Effective Go 中文翻译] 第一篇

Go语言上手 | 青训营笔记

Go语言上手 | 青训营笔记

Python 程序员快速学 Go+ 系列,第一篇+官方手册翻译