defer 表示后续的调用
defer fmt.Println(1)
defer fmt.Println(2)//输出的是2, 1
//最后的小括号表示调用某函数
// 表示匿名函数
func() {
fmt.Println(1)
}()
defer func() {
fmt.Println(1)
}()
func B(){
//defer 需要放在panic之前,然后有panic的话,就能将程序recover过来
defer func(){
if err := recover(); err!=nil{
fmt.Println("a");
}
}()
panic("panic in b")
}
panic/recover(只能在defer里面调用)
1.1 struct 类似结构体
type person struct {
Name string
Age int
}
func main(){
a:=person{} //引用是大括号
a.Name = "j"
a.Age = 19
b:=person{
Name: "joe",
Age: 19
} //引用是大括号
//加个取地址符号,然后赋值的时候,不用加* ,这样b就是取地址
b:= &person{
Name: "joe",
Age: 19
} //引用是大括号
b.Name = "aa"
b:= &struct {
Name string
Age int
}{
Name: "joe",
Age: 19
} //匿名结构
}
赋值只是值的拷贝,这样在函数里面修改后,外面的还是维持原样,如果需要的话,就用指针的形式来传递地址。
并发concurrency
很多人都是冲着 Go 大肆宣扬的高并发而忍不住跃跃欲试,但其实从
源码的解析来看,goroutine 只是由官方实现的超级“线程池”而已。
不过话说回来,每个实例 4-5KB 的栈内存占用和由于实现机制而大幅
减少的创建和销毁开销,是制造 Go 号称的高并发的根本原因。另外,
goroutine 的简单易用,也在语言层面上给予了开发者巨大的便利。
并发不是并行:Concurrency Is Not Parallelism
并发主要由切换时间片来实现“同时”运行,在并行则是直接利用
多核实现多线程的运行,但 Go 可以设置使用核数,以发挥多核计算机
的能力。
Goroutine 奉行通过通信来共享内存,而不是共享内存来通信。
最简单的使用方式,用go关键字运行goroutine ,通过通信来实行内存分配
package main
import (
"fmt"
"time"
)
func main() {
go Go() //goroutine
time.Sleep(2 * time.Second)
}
func Go() {
fmt.Println("Go Go Go")
}
Channel
Channel 是 goroutine 沟通的桥梁,大都是阻塞同步的
通过 make 创建,close 关闭
Channel 是引用类型
可以使用 for range 来迭代不断操作 channel
可以设置单向或双向通道
可以设置缓存大小,在未被填满前不会发生阻塞
Select
可处理一个或多个 channel 的发送与接收
同时有多个可用的 channel时按随机顺序处理
可用空的 select 来阻塞 main 函数
可设置超时
package main
import (
"fmt"
)
func main() {
c := make(chan bool)
go func() {
fmt.Println("Go Go Go")
c <- true //将true放入c的channel
}()
<-c //表示取出c,知道c的channel有值才会结束,不然会一直等待
}
func Go() {
fmt.Println("Go Go Go")
}
for range的使用
for v := range c {
fmt.Println(v)
}
package main
import (
"fmt"
)
func main() {
c := make(chan bool) //直接make的话是双向通道
c := make(chan bool,1) //表示有缓存,就要先输入,后输出,
go func() {
fmt.Println("Go Go Go")
c <- true
close(c) //关闭c的channel
}()
for v := range c {
fmt.Println(v)
}
}
运行十个进程的
package main
import (
"fmt"
"runtime"
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU()) //确定cup的核数
c := make(chan bool, 10) //设置一个缓存长度为10的channel
for i := 0; i < 10; i++ {
go Go(c, i)
}
for i := 0; i < 10; i++ {
<-c
}
}
func Go(c chan bool, index int) {
a := 1
for i := 0; i < 1000000; i++ {
a += i
}
fmt.Println(index, a)
c <- true
}
//用sync实现,先增加十个,然后在主线程Wait,次线程Done,关闭10次,然后程序就会关闭,这个和上面那种方式类似,这个是同步包,需要传递指针,这样才能改变数据,不然只是单纯的值复制
package main
import (
"fmt"
"runtime"
"sync" //同步
)
func main() {
runtime.GOMAXPROCS(runtime.NumCPU()) //确定cup的核数
wg := sync.WaitGroup{}
wg.Add(10)
for i := 0; i < 10; i++ {
go Go(&wg, i)
}
wg.Wait()
}
func Go(wg *sync.WaitGroup, index int) {
a := 1
for i := 0; i < 1000000; i++ {
a += i
}
fmt.Println(index, a)
wg.Done()
}
select的使用方式
// You can edit this code!
// Click here and start typing.
package main
import (
"fmt"
)
func main() {
c1, c2 := make(chan int), make(chan string)
o := make(chan bool)
go func() {
a, b := false, false
for {
select {
case v, ok := <-c1:
if !ok {
if !a {
o <- true
a = true
}
break
}
fmt.Println("c1", v)
case v, ok := <-c2:
if !ok {
if !b {
o <- true
a = true
}
break
}
fmt.Println("c2", v)
}
}
}()
c1 <- 1
c2 <- "hu"
c1 <- 3
c2 <- "aaaa"
close(c1)
close(c2)
for i := 0; i < 2; i++ {
<-o
}
}