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不阻塞。从而实现并行效果。
以上是关于go语言第一篇的主要内容,如果未能解决你的问题,请参考以下文章