GO协程间通信的同步问题

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)

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值