go语言的创作者的一句话:“不要通过共享内存来通讯,要通过通讯来共享内存”
我们已经使用过channel, 但是在前面几例中都是使用time.Sleep()方法来保障主线不被那么快的结束,从而让子协程中的fmt.print()有机会被输出。 但是这样很不友好,也不应该被使用,用channel通讯来试试吧
代码1
代码思路:
每次写入 in chan时也同时写入done chan, done chan被阻塞在主线程中与in chan相互等待,读取完后才会退出
package main
import (
"fmt"
"time"
)
type Worker struct {
in chan int
done chan bool
}
func (work Worker)DoWork() {
for c := range work.in{
fmt.Printf("get data : %c\n",c)
go func() {
fmt.Println("insert to done channel ")
work.done <- true
}()
}
}
func CreateWorker()(worker Worker) {
worker = Worker{
in: make(chan int),
done: make(chan bool),
}
go worker.DoWork()
return
}
func main() {
work := CreateWorker()
for i:=0;i<10 ;i++ {
time.Sleep(time.Second)
work.in <- 'a'+i
}
for i:=0;i<10;i++ {
time.Sleep(time.Second)
work.in <- 'A'+i
}
fmt.Println("read from done channel ",<-work.done)
fmt.Println("============end================")
}
运行结果:
get data : a
insert to done channel
get data : b
insert to done channel
get data : c
insert to done channel
get data : d
insert to done channel
get data : e
insert to done channel
get data : f
insert to done channel
get data : g
insert to done channel
get data : h
insert to done channel
get data : i
insert to done channel
get data : j
insert to done channel
get data : A
insert to done channel
get data : B
insert to done channel
get data : C
insert to done channel
get data : D
insert to done channel
get data : E
insert to done channel
get data : F
insert to done channel
get data : G
insert to done channel
get data : H
insert to done channel
get data : I
insert to done channel
read from done channel true
============end================
get data : J
结果分析:
为了让结果打印的更清晰,让每次输入都睡眠一秒。
fmt.Println("read from done channel ",<-work.done)
这条语句只打印了一次,把这条语句拆开来看
value := <-work.done
fmt.Println("read from done channel ",value)
因为代码一直被阻塞在value := <-work.done这里,所以只有读完后才能执行到fmt.Println()
代码2
代码思路:
利用golang提供的sync.WaitGroup来完成
package main
import (
"fmt"
"sync"
)
type Worker struct {
in chan int
wg *sync.WaitGroup
}
func (work Worker)DoWork(wg *sync.WaitGroup) {
for c := range work.in{
fmt.Printf("get data : %c\n",c)
wg.Done()
}
}
func CreateWorker(wg *sync.WaitGroup)(worker Worker) {
worker = Worker{
in: make(chan int),
wg: wg,
}
go worker.DoWork(wg)
return
}
func main() {
var wg sync.WaitGroup
wg.Add(20)
work := CreateWorker(&wg)
for i:=0;i<10 ;i++ {
work.in <- 'a'+i
}
for i:=0;i<10;i++ {
work.in <- 'A'+i
}
wg.Wait()
}
运行结果:
get data : a
get data : b
get data : c
get data : d
get data : e
get data : f
get data : g
get data : h
get data : i
get data : j
get data : A
get data : B
get data : C
get data : D
get data : E
get data : F
get data : G
get data : H
get data : I
get data : J
用协程通讯来统计二叉树的最大值
node.go
package node
type Node struct {
LeftNode *Node
RightNode *Node
Value int
}
func (node Node)Do(f func(n *Node)) {
f(&node)
if node.LeftNode != nil {
node.LeftNode.Do(f)
}
if node.RightNode != nil{
node.RightNode.Do(f)
}
}
func (node Node)DoWithChan()chan *Node {
out := make(chan *Node)
go func() {
node.Do(func(n *Node) {
out <- n
})
close(out)
}()
return out
}
main.go
package main
import (
"fmt"
"go_study/tree/node"
"strconv"
)
func buildTree() node.Node {
var tree node.Node
tree.Value = 0
tree.LeftNode = new(node.Node)
tree.LeftNode.Value = 1
tree.LeftNode.LeftNode = new(node.Node)
tree.LeftNode.LeftNode.Value = 3
tree.LeftNode.LeftNode.LeftNode = new(node.Node)
tree.LeftNode.LeftNode.LeftNode.Value = 5
tree.LeftNode.LeftNode.RightNode = new(node.Node)
tree.LeftNode.LeftNode.RightNode.Value = 6
tree.RightNode = new(node.Node)
tree.RightNode.Value = 2
tree.RightNode.LeftNode = new(node.Node)
tree.RightNode.LeftNode.Value = 4
tree.RightNode.LeftNode.RightNode = new(node.Node)
tree.RightNode.LeftNode.RightNode.Value = 7
return tree
}
func main() {
tree := buildTree()
outChan := tree.DoWithChan()
maxValue := 0
for c := range outChan{
if maxValue < c.Value {
maxValue = c.Value
}
}
fmt.Println("max value is ",maxValue)
}