实现高并发:
协程:用户态,轻量级线程,栈kb级别
go 函数名():开启一个协程
线程:内核态,线程包含多个协程,栈mb级别
func newTask(){
i:=0
for{
i++
fmt.Println("new Goroutine : i= %d\n",i)
time.Sleep(1*time.Second)
}
}
func main(){
//创建协程
go newTask()
}
用go承载一个形参为空,返回值为空的函数
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
go func() {
defer fmt.Println("A.defer")
func() {
defer fmt.Println("B.defer")
fmt.Println("B")
}()
fmt.Println("A")
}() //不要忘记() 匿名函数}后面要加一对小括号
//死循环,目的不让主goroutine结束
for {
time.Sleep(1*time.Second)
}
}
输出结果: B B.defer A A.defer
func main() {
go func() {
defer fmt.Println("A.defer")
func() {
defer fmt.Println("B.defer")
//退出当前的goroutine
//调用 runtime.Goexit() 将立即终止当前 goroutine 执⾏,调度器确保所有已注册 defer 延迟调用被执行。
runtime.Goexit()
fmt.Println("B")
}()
fmt.Println("A")
}()
for {
time.Sleep(1*time.Second)
}
}
输出结果: B.defer A.defer
用go承载一个有形参,有返回值的函数
func main(){
go func(a int ,b int) bool{
fmt.Println("a=",a,",b=",b)
return true
}(10,20)
}
输出结果:a=10,b=20
channel
协程间的通信:提倡通过通信实现共享内存而不是通过共享内存实现通信
channel <- value //发送value到channel
<-channel //接收并将其丢弃
x := <-channel //从channel中接收数据,并赋值给x
x, ok := <-channel //功能同上,同时检查通道是否已关闭或者是否为空
make(chan 元素类型,[缓冲大小])
func main(){
c := make(chan int)
go func() {
defer fmt.Println("子go程结束")
fmt.Println("子go程正在运行……")
c <- 666 //666发送到c
}()
num := <-c //从c中接收数据,并赋值给num
fmt.Println("num = ", num)
fmt.Println("main go程结束")
}
}
输出:
子go程正在运行……
子go程结束
num=666
main go程结束
无缓冲 :通信双方必须要确保对方读取到数据才能退出通道,去做其他事情。
有缓冲 :收发数据不受对方影响。发送完数据后不管接收方有没有读取都可以去做其他事。
func main(){
c := make(chan int)
go func() {
defer fmt.Println("子go程结束")
fmt.Println("子go程正在运行……")
c <- 666 //666发送到c
}()
num := <-c //从c中接收数据,并赋值给num
fmt.Println("num = ", num)
fmt.Println("main go程结束")
}
}
输出: 子go程正在运行…… 子go程结束 num=666 main go程结束
当channel已满,再向里面写数据,就会阻塞
当channel为空,从里面取数据也会阻塞
关闭channel
package main
import (
"fmt"
)
func main() {
c := make(chan int)
go func() {
for i := 0; i < 5; i++ {
c <- i
}
close(c) //关闭channel
}()
for {
//ok为true说明channel没有关闭,为false说明管道已经关闭
if data, ok := <-c; ok {
fmt.Println(data)
} else {
break
}
}
fmt.Println("Finished")
}
- channel不像文件一样需要经常去关闭,只有当确实没有数据发送,或者想显式的结束range循环之类的,才去关闭channel;
- 关闭channel后,无法向channel 再发送数据(引发 panic 错误后导致接收立即返回零值);
- 关闭channel后,可以继续从channel接收数据;
- 对于nil channel,无论收发都会被阻塞。
channel与range
可以使用range来迭代不断操作channel
for data := range c {
fmt.Println(data)
}
channel与select
单流程下一个go只能监控一个channel的状态,select可以完成监控多个channel的状态。
select {
case <- chan1:
// 如果chan1成功读到数据,则进行该case处理语句
case chan2 <- 1:
// 如果成功向chan2写入数据,则进行该case处理语句
default:
// 如果上面都没有成功,则进入default处理流程
}
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 1, 1
for {
select {
case c <- x:
//如果通道c可写,就执行下面语句
x, y = y, x+y
case <-quit:
//如果通道quit可读,就执行下面语句
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 6; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}