8.5 并发的循环
知识点
- 1.和switch语句稍微有点相似,也会有几个case和最后的default选择支
- 2.每一个case代表一个通信操作(在某个channel上进行发送或者接收)并且会包含一些语句组成的一个语句块
- 3.一个接收表达式可能只包含接收表达式自身,或者包含在一个简短的变量声明中
- 4.select会等待case中有能够执行的case时去执行,执行后,其他通信是不会执行
- 5.没有任何case的select会永远等待下去,写作select{}
- 6.time.Tick所建goroutine依然运行,但没有其他channel接收其值,导致goroutine泄露,因此使用代码所示方式
- 7.对一个nil的channel发送和接收操作会永远阻塞
- 8.在select语句中操作nil的channel永远都不会被select到
代码
func test_concurrent(num int64) {
/*
练习 8.4: 修改reverb2服务器,
在每一个连接中使用sync.WaitGroup来计数活跃的echo goroutine。
当计数减为零时,关闭TCP连接的写入,像练习8.3中一样。
验证一下你的修改版netcat3客户端会一直等待所有的并发“喊叫”完成,
即使是在标准输入流已经关闭的情况下。
*/
listener, err := net.Listen("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Fatal(err)
continue
}
if num == 87 {
go handleConn_concurrent_87(conn)
}else {
go handleConn_concurrent(conn)
}
}
test_thr3_concurrent()
}
func handleConn_concurrent(c net.Conn) {
input := bufio.NewScanner(c)
var wg sync.WaitGroup // number of working goroutines
for input.Scan() {
str := input.Text()
if str == "EOF" {
break
}
if len(str) > 0 {
wg.Add(1)
go func(c net.Conn, shut string, delay time.Duration) {
defer wg.Done()
fmt.Fprintf(c, "\t", strings.ToUpper(shut))
time.Sleep(delay)
fmt.Fprintf(c, "\t", shut)
time.Sleep(delay)
fmt.Fprintf(c, "\t", strings.ToLower(shut))
}(c , str, 1*time.Second)
}
}
wg.Wait()
c.Close()
}
func test_thr3_concurrent() {
/*
练习 8.5: 使用一个已有的CPU绑定的顺序程序,
比如在3.3节中我们写的Mandelbrot程序计算程序,
并将他们的主循环改为并发形式,使用channel来进行通信。
在多核计算机上这个程序得到了多少速度上的改进?
使用多少个goroutine是最合适的呢?
*/
color_chan := make(chan color.Color)
var wg sync.WaitGroup // number of working goroutines
fmt.Println(time.Now())
fileName := "mandelbrot_concurrent.png"
//绘制Mandelbrot图像
const (
xmin, ymin, xmax, ymax = -2, -2, +2, +2
width, height = 1024, 1024
)
img := image.NewRGBA(image.Rect(0, 0, width, height))
for py := 0; py < height; py++ {
yyy := float64(py) / height * (ymax - ymin) + ymin
for px := 0; px < width; px++ {
xxx := float64(px) / width * (xmax - xmin) + xmin
z := complex(xxx, yyy)
wg.Add(1)
go func(zz complex128) {
defer wg.Done()
color_chan <- mandelbrot_concurrent(zz)
}(z)
colo := <- color_chan
img.Set(px, py, colo)
}
}
fmt.Println(time.Now())
wg.Wait()
close(color_chan)
file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0666)
defer file.Close()
if err != nil {
fmt.Println(err)
}
png.Encode(file, img)
}
func mandelbrot_concurrent(z complex128) color.Color {
const iterations = 200
const contrast = 15
var v complex128
for n := uint8(0); n < iterations; n++ {
v = v * v + z
if cmplx.Abs(v) > 2 {
return color.Gray{255 - contrast * n}
}
}
return color.Black
}
——不足之处,欢迎补充——
备注
《Go 语言圣经》
- 学习记录所使用的GO版本是1.8
- 学习记录所使用的编译器工具为GoLand
- 学习记录所使用的系统环境为Mac os
- 学习者有一定的C语言基础
代码仓库