1.Go主线程也可称为线程,也可以理解为进程,一个Go主线程上可以起多个协程,可以理解协程为轻量级的线程,资源消耗较小
2.协程特点:有独立的栈空间;共享程度堆空间;调度由用户控制;是轻量级的线程
package main
import (
"fmt"
"strconv"
"time"
)
/**
main主线程和test协程同时执行
*/
func main() {
go test() //开启协程
for i := 0; i < 10; i++ {
fmt.Println("hello wrold ", strconv.Itoa(i+1), "次")
time.Sleep(time.Second)
}
}
func test() {
for i := 0; i < 10; i++ {
fmt.Println("hello golang ", strconv.Itoa(i+1), "次")
time.Sleep(time.Second)
}
}
主线程等待所有goroutine全部完成时间很难确定,等待时间短协程会随主线程的退出而销毁,等待时间长,不利程序运行。另外全局变量加锁同步实现通讯,也不利于多协程对全局变量的读写操作。
package main
import (
"fmt"
)
func main() {
//声明一个可读可写管道,初始化管道必须make
var intChan chan int
intChan = make(chan int, 3)
//声明为只能写
var chan1 chan<- int
chan1 = make(chan int, 3)
chan1 <- 11
//声明为只能读
//var chan2 <-chan int
//向管道写入数据,写入数据不能超过长度
intChan <- 10
num := 211
intChan <- num
intChan <- 985
//向管道读取数据,如果已经没有数据在读取,会报deadlock错误
n := <-intChan
fmt.Println("取出的数据", n)
//查看管道长度和容量
fmt.Printf("长度=%v,容量=%v\n", len(intChan), cap(intChan))
//关闭channel,关闭后只能读,不能写入
close(intChan)
//channel遍历,不能用普通的for循环
//必须关闭channel,否则报错
for i := range intChan {
fmt.Println(i)
}
intChan1 := make(chan int, 10)
strChan := make(chan string, 10)
for i := 0; i < 10; i++ {
intChan1 <- i
strChan <- "hello" + fmt.Sprintf("%d", i)
}
selectChannel(intChan1, strChan)
}
//不使用close()也可以从管道中取出数据
//实际开发中,不好确定什么时候关闭管道,可以用select方式解决
func selectChannel(intChan1 chan int, strChan chan string) {
for {
select {
//如果intChan一直没有关闭,不会一直堵塞至死锁,自动跳到下一个case
case v := <-intChan1:
fmt.Printf("从intChan1中取数据%d\n", v)
case v := <-strChan:
fmt.Printf("从strChan中取数据%s\n", v)
default:
fmt.Println("都取不到了")
return
}
}
}
package main
import "fmt"
func writeData(intChan chan int) {
for i := 0; i < 50; i++ {
intChan <- i
fmt.Println("写入的数据", i)
}
//没关闭前读线程已经开始工作
//如果没有关闭,编译器会一直等待下一个写入的内容,导致死锁
close(intChan)
}
func readData(intChan chan int, exitChan chan bool) {
//如果此协程发生错误,捕获异常,不影响其他协程,主线程不受影响
defer func() {
//捕获readData抛出的panic
err := recover()
if err != nil {
fmt.Println("发生错误")
}
}()
for {
v, ok := <-intChan
if !ok {
break
}
fmt.Println("读取到的数据", v)
}
exitChan <- true
close(exitChan)
}
func main() {
intChan := make(chan int, 50)
//借助此管道判断两个协程什么时候结束
exitChan := make(chan bool, 1)
go writeData(intChan)
go readData(intChan, exitChan)
//解决主线程等待协程时间问题
for {
_, ok := <-exitChan
if !ok {
break
}
}
}