题目一:需要实现两个goroutine,这里分别命名为A、B,其中A用来产生随机数并将随机数写入channel中,B用来从channel中读取随机数并将随机数打印到标准输出,最后要求B最多在标准输出打印出五个随机数。
实现上述题目需要注意以下几点:
-
Go中goroutine是非阻塞的。
-
channel初始化为无缓冲时,读写都是阻塞的,通常用for循环来读取channel中的数据,当管道关闭后,for循环退出。
-
Go中专用select case语法来从管道中读取数据。
案例如下:
package main
import (
"fmt"
"math/rand"
"sync"
)
func main() {
printChan := make(chan int)
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
for i := 0; i < 5; i++ {
printChan <- rand.Intn(5)
}
close(printChan)
}()
go func() {
defer wg.Done()
for i := range printChan {
fmt.Println(i)
}
}()
wg.Wait()
}
输出结果如下:
题目二:实现阻塞读且并发安全的map
题目二描述:Go中map如何实现当key不存在的时候,get操作等待,一直到key存在或超时,此时应保证程序并发安全问题。
需注意以下几点:
-
Go实现阻塞通常使用channel。
-
并发安全就要考虑使用锁机制,也就是给代码块读写锁,这时要注意的是,在代码块执行完毕之后,关闭读写锁。
-
map每个键值都需要有一个阻塞goroutin的channel,来实现map的阻塞读。
案例如下:
package main
import (
"sync"
)
type Map struct {
MapChan map[string]*Entry
RMX *sync.RWMutex
}
type Entry struct {
Ch chan struct{}
Value interface{}
IsExist bool
}
func (m *Map) Out(key string, val interface{}) {
m.RMX.Lock()
defer m.RMX.Unlock()
item, ok := m.MapChan[key]
if !ok {
m.MapChan[key] = &Entry{
Value: val,
IsExist: true,
}
return
}
item.Value = val
if !item.IsExist {
if item.Ch != nil {
close(item.Ch)
item.Ch = nil
}
}
}
扫码关注公众号,获取更多优质内容。