简介
go
配置
GOMAXPROCS 设置逻辑CPU数量,个别状况下应用CPU外围数量值.应用足够的线程来进步golang的并行执行效率.如果你的业务是IO密集型则能够设置数倍与CPU外围数的值来失去更好的性能.如果Go程序在容器中执行则须要依据状况缩小该值得,因为容器中无奈应用到宿主机的全副外围.设置更小的值能够防止线程切换的开销.
应用channel进行协程通信
定义通道
ch1 := make(chan string) //定义了一个无缓冲的string通道
ch2 := make(chan string , 4) //定义了一个4个元素的string通道
通道操作符
ch1 <- "Chengdu" //向通道写入数据
itemOfCh1 := <- ch1 //从ch1通道读取一条数据
<- ch1 //读取通道的下一个值
var in_only chan<- int //只能接管通道
var out_only <-chan int //只读取的通道
close(ch) //敞开通道
通道阻塞
默认状况通道是同步无缓冲的,在接受方未筹备好之前发送方是阻塞的.通道中没有数据则接管方也是阻塞的.
package main
import (
"fmt"
"time"
)
func f1(in chan int) {
data := <-in
fmt.Println(data)
}
func main() {
out := make(chan int)
out <- 2
fmt.Println(v)
go f1(out)
time.Sleep(100 * time.Millisecond)
}
批改 out:=make(chan int , 1)
应用信号量
能够通过信号量来让主协程期待子协程的实现退出执行.
package main
import (
"fmt"
"time"
)
func f1(in chan int, done chan int) {
data := <-in
fmt.Println(data)
time.Sleep(10e9)
done <- 1
}
func main() {
out := make(chan int)
done := make(chan int)
go f1(out, done)
out <- 2
<-done
}
输入 2 之后10秒后程序才会退出,咱们就不须要应用sleep来让主过程执行.
敞开通道
显式的敞开通道,敞开通道示意发送者不会有新的数据发送给接受者了.只有发送者须要敞开通道.
ch := make(chan int )
defer close(ch)
data,ok := <-ch //接管到数据则ok为 true,应用ok能够检测通道是否敞开或者阻塞
上面这种状况,读取通道在主过程不会报死锁谬误,因为查看到通道敞开后就不进行通道读取跳出循环,因而不会再继读没有写入的通道.所以没有死锁.
package main
import "fmt"
func makeStream(n int) chan bool {
ch := make(chan bool, n)
go func() {
for i := 0; i < n; i++ {
ch <- true
}
close(ch)
}()
return ch
}
func main() {
stream := makeStream(5)
for {
v, ok := <-stream
if !ok {
break
}
fmt.Println(v)
}
}
应用select 切换协程
selectfor
default
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
for i := 0; i < 10; i++ {
ch1 <- fmt.Sprintf("A%d", i)
}
}()
go func() {
for i := 0; i < 10; i++ {
ch2 <- fmt.Sprintf("B%d", i)
}
}()
go func() {
for {
select {
case v := <-ch1:
fmt.Println(v)
case v := <-ch2:
fmt.Println(v)
}
}
}()
time.Sleep(1e9)
}
能够应用这种模式做为服务端来循环解决客户申请
计时器(Ticker)
type Ticker struct {
C <-chan Time // The channel on which the ticks are delivered.
r runtimeTimer
}
定时器的C变量会依据你创立的定时器工夫,在给定工夫外向该通道写入工夫
package main
import (
"fmt"
"time"
)
func main() {
t := time.NewTicker(time.Second)
go func() {
for {
v := <-t.C
fmt.Println(v)
}
}()
time.Sleep(10e9) // <-time.After(10e9) 应用通道来设置超时
}
time.Tick(duration)time.NewTicker(1e9).Ctime.After(duration)
协程的复原
panic
package main
import (
"log"
"time"
)
func doWork() {
time.Sleep(4e9)
panic("fk")
}
func main() {
go func() {
for {
log.Printf("another worker")
time.Sleep(1e9)
}
}()
go func() {
defer func() {
if err := recover(); err != nil {
log.Printf("出问题了 %s", err)
}
}()
doWork()
}()
time.Sleep(10e9)
}
应用锁还是通道
在一种场景下,有多个工作,一个worker解决一项工作.这种场景很适宜应用通道和协程来解决问题
package main
type Task struct{}
type Result struct{}
func process(Task *Task) Result {
return Result{}
}
func main() {
tasks, results := make(chan Task), make(chan Result)
workCount := 10
//创立工作
go func() {
for i := 0; i < workCount; i++ {
tasks <- Task{}
}
}()
//启动worker
for i := 0; i < workCount; i++ {
go func() {
for {
t := <-tasks
result := process(&t) //解决数据
results <- result //写入构造
}
}()
}
//生产后果
}
-
应用锁的情景:
- 访问共享数据结构中的缓存信息
- 保留应用程序上下文和状态信息数据
-
应用通道的情景:
- 与异步操作的后果进行交互
- 散发工作
- 传递数据所有权