1)channel可以声明为只读,或只写性质
案例如下:
package main
import (
_"fmt"
)
func main() {
// 管道可以声明为只读或者只写
// 1. 在默认情况下,管道是双向的
// var chan1 chan int // 可读可写
// 2. 声明为只写
var chan2 chan<- int
chan2 = make(chan int,3)
chan2<- 20
// num := <- chan2
// fmt.Println(num)
// 3. 声明为只读
var chan3 <-chan int
nm2 := <-chan3
}
2)channel 只读和只写的最佳实践案例
package main
import (
"fmt"
)
// 只写操作
func send(ch chan<- int, exitChan chan struct{}) {
for i := 0; i < 100; i++ {
ch<- i
}
close(ch)
var a struct{}
exitChan <- a
}
// 只读操作
func recv(ch <-chan int,exitChan chan struct{}) {
for {
v, ok := <- ch
if !ok {
break
}
fmt.Println(v)
}
var a struct {}
exitChan<- a
}
func main() {
var ch chan int
ch = make(chan int, 10)
exitChan := make(chan struct{}, 2)
go send(ch, exitChan)
go recv(ch, exitChan)
var total = 0
for _ = range exitChan {
total++
if total == 2 {
break
}
}
fmt.Println("结束")
}
3)使用select 解决从管道取数据的阻塞问题
package main
import (
"fmt"
)
func main() {
// 使用 select解决从管道取数据的阻塞问题
// 1. 定义一个管道 10个数据int
intChan := make(chan int,10)
for i := 0; i < 10; i++ {
intChan<- i
}
// 2. 定义一个管道 5个数据string
stringChan := make(chan string, 5)
for i := 0; i < 5; i++ {
stringChan<- "hello" + fmt.Sprintf("%d",i)
}
// 传统的方法在遍历管道时,如果不关闭会阻塞而导致deadlock
// 问题:在实际开发中,可能不好确定什么时候关闭管道
// 可以使用select 方式解决
label:
for {
select {
case v := <-intChan : // 注意:这里,如果intChan一致没有关闭,不会一直阻塞而deadlock
// 会自动地到下一个case匹配
fmt.Printf("从intChan读取的数据%d\n",v)
case v := <- stringChan:
fmt.Printf("从stringChan读取的数据%v\n",v)
default:
fmt.Printf("都取不到了,退出...")
break label
}
}
}
4)goroutine中使用recover,解决协程中出现panic,导致程序崩溃的问题
说明:如果我们起了一个协程,但是这个协程出现了panic,如果我们没有捕获这个panic,就会造成整个程序的崩溃,这时我们可以在goroutine中使用recover来捕获panic进行处理,这样即使这个协程发生问题,但是主线程仍然不受影响,可以继续执行
代码实现:
package main
import (
"fmt"
"time"
)
// 函数
func sayHello() {
for i := 0; i < 10; i++ {
time.Sleep(time.Second)
fmt.Println("hello, world")
}
}
// 函数
func test() {
// 这里我们可以使用 defer + recover
defer func() {
// 捕获test中抛出的panic
if err := recover();err != nil {
fmt.Println("test() 发生错误", err)
}
}()
// 定义了一个map
var myMap map[int]string
myMap[0] = "golang" // error
}
func main() {
go sayHello()
go test()
for i := 0; i < 10; i++ {
fmt.Println("main() ok=",i)
time.Sleep(time.Second)
}
}