Open
Description
- 下面代码会触发异常吗
func main() {
runtime.GOMAXPROCS(1)
int_chan := make(chan int, 1)
string_chan := make(chan string, 1)
int_chan <- 1
string_chan <- "hello"
select {
case value := <-int_chan:
fmt.Println(value)
case value := <-string_chan:
panic(value)
}
}
解析:可能触发异常,也可能不会触发异常。
channel
特性说明
-
给一个
nil channel
发送数据,造成永远阻塞; -
从一个
nil channel
接收数据,造成永远阻塞; -
给一个已经关闭的
channel
发送数据,引起panic
; -
从一个已经关闭的
channel
接收数据,如果缓冲区中为空,则返回一个零值,缓冲区不为空,返回已缓冲数据; -
无缓冲的
channel
是同步的,而有缓冲的channel
是非同步的。
- 下面代码输出什么
func main() {
ch := make(chan int, 100)
// A
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
}()
// B
go func() {
for {
a, ok := <-ch
if !ok {
fmt.Println("close")
return
}
fmt.Println("a: ", a)
}
}()
close(ch)
fmt.Println("ok")
time.Sleep(time.Second * 10)
}
解析:当 A
协程还没起时,主协程已经将 channel
关闭了,当 A
协程往关闭的 channel
发送数据时会 panic
,panic: send on closed channel
。
- 下面的代码有什么问题
func Stop(stop <-chan bool) {
close(stop)
}
解析:有方向的 channel
不可以被关闭。
- 下面代码输出什么
func main() {
var ch chan int
select {
case v, ok := <-ch:
println(v, ok)
default:
println("default")
}
}
输出:default
。
解析:ch
为 nil
,读写都会阻塞。
- 下面的代码输出什么
var o = fmt.Print
func main() {
c := make(chan int, 1)
for range [3]struct{}{} {
select {
default:
o(1)
case <-c:
o(2)
c = nil
case c <- 1:
o(3)
}
}
}
输出:321
解析:第一次循环,写操作已经准备好,执行 o(3)
,输出 3
;第二次,读操作准备好,执行 o(2)
,输出 2
并将 c
赋值为 nil
;第三次,由于 c
为 nil
,走的是 default
分支,输出 1
。
- 下面的代码有什么问题
type data struct {
sync.Mutex
}
func (d data) test(s string) {
d.Lock()
defer d.Unlock()
for i:=0;i<5 ;i++ {
fmt.Println(s,i)
time.Sleep(time.Second)
}
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
var d data
go func() {
defer wg.Done()
d.test("read")
}()
go func() {
defer wg.Done()
d.test("write")
}()
wg.Wait()
}
解析:锁失效。将 Mutex
作为匿名字段时,相关的方法必须使用指针接收者,否则会导致锁机制失效。
修复代码:
type data struct {
*sync.Mutex // 嵌入 *Mutex 来避免复制的问题,但是需要初始化
}
func (d data) test(s string) { // 值方法
d.Lock()
defer d.Unlock()
for i := 0; i < 5; i++ {
fmt.Println(s, i)
time.Sleep(time.Second)
}
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
d := data{new(sync.Mutex)} // 初始化
go func() {
defer wg.Done()
d.test("read")
}()
go func() {
defer wg.Done()
d.test("write")
}()
wg.Wait()
}