Go:Goroutine 和 Channel

协程 Coroutine

  • 轻量级 “线程”
  • 非抢占式多任务处理,由协程主动交出控制权
  • 编译器、解释器、虚拟机层面的多任务
  • 多个协程可能在一个或多个线程上运行

非抢占式任务处理实例

package main

import (
	"fmt"
	"time"
)

func main() {
	for i:= 0; i < 10; i++ {
		go func(i int) {
			for {
				fmt.Printf("Hello from" +
					"goroutine %d\n", i)
			}
		}(i)
	}
	time.Sleep(time.Millisecond)
}
go run goroutine.go
go run -race goroutine.go   //数据冲突检测
  • 子程序是协程的一个特例

在这里插入图片描述
其他语言中的协程

  • C++ :Boost.Coroutine

  • java : 不支持

  • python

    • 使用yield关键字实现协程
    • python 3.5 加入了async def对协程原生支持
  • go
    在这里插入图片描述
    goroutine的定义

  • 任何函数只需要加上go就能送给调度器运行

  • 不需要在定义时区分是否是异步函数

  • 调度器在合适的点进行切换

  • 使用-race 来检测数据访问冲突

goroutine 可能得切换点

  • I/O,select
  • channel
  • 等待锁
  • 函数调用(有时)
  • runtime.Gosched
  • 只是参考,不能保证切换,不能保证在其他地方不切换

Channel

在这里插入图片描述
channel 是goroutine和goroutine之间的交互

channel的创建实例:

package main

import (
	"fmt"
	"time"
)

func channDemo() {
	//var c chan int  //c == nil
	c := make(chan int)
	/*channel创建之后需要有goroutine接收,
	   不然会产生死锁*/
	go func() {
		for {
			n := <- c
			fmt.Println(n)
		}
	}()
	c <- 1
	c <- 2
	time.Sleep(time.Millisecond)
}

func main() {
	channDemo()
}

channel能作为函数参数和返回值

func creatWorker(id int) chan<- int{
	c := make(chan int)
	go func() {
		for {
			fmt.Printf("Worker %d received %c\n",
				id, <- c)
		}
	}()
	return c
}

func channDemo() {
	var channels [10] chan<- int
	for i := 0; i < 10; i++ {
		//创建10个channel
		channels[i] = creatWorker(i)
	}

	//分别给10个channel发送数据
	for i := 0; i < 10; i++ {
		channels[i] <- 'a' + i
	}
	for i := 0; i < 10; i++ {
		channels[i] <- 'A' + i
	}
	time.Sleep(time.Millisecond)
}

func main() {
	channDemo()
}

channel
buffered channel
range

package main

import (
	"fmt"
	"time"
)

/*func worker(id int, c chan int) {
	for {
		fmt.Printf("Worker %d received %c\n",
			id, <- c)
	}
}*/

func worker(id int, c chan int) {
	for n := range c{
		/*n, ok := <- c
		if !ok {
			break
		}*/
		fmt.Printf("Worker %d received %d\n",
			id, n)
	}
}
func creatWorker(id int) chan<- int{
	c := make(chan int)
	go worker(id, c)
	return c
}
/*
func channDemo() {
	//var c chan int  //c == nil
	c := make(chan int)
	//channel创建之后需要有goroutine接收,不然会产生死锁
	go worker(0, c)
	c <- 1
	c <- 2
	time.Sleep(time.Millisecond)
}*/
func channDemo() {
	var channels [10] chan<- int
	for i := 0; i < 10; i++ {
		//创建10个channel
		channels[i] = creatWorker(i)
	}

	//分别给10个channel发送数据
	for i := 0; i < 10; i++ {
		channels[i] <- 'a' + i
	}
	for i := 0; i < 10; i++ {
		channels[i] <- 'A' + i
	}
	time.Sleep(time.Millisecond)
}
func bufferedChannel() {
	//创建channel,缓冲区大小为3
	c := make(chan int, 3)
	go worker(0, c)

	c <- 'a'
	c <- 'b'
	c <- 'c'
	time.Sleep(time.Millisecond)
}

// 由发送发发送数据发送结束标志
func channelClose() {
	c := make(chan int)
	go worker(0, c)

	c <- 'a'
	c <- 'b'
	c <- 'c'

	close(c)
	time.Sleep(time.Millisecond)
}
func main() {
	fmt.Println("Channel as first-class citizen")
	channDemo()
	fmt.Println("Buffered channel")
	bufferedChannel()
	fmt.Println("Channel close and range")
	channelClose()
}

CSP: 不要通过共享内存来通信,通过通信来共享内存

使用Channel等待任务结束

例一:使用Channel来等待goroutine结束

  • waitGroup
package main

import (
	"fmt"
	"sync"
)


func doWorker(id int,
	w worker) {
	for n := range w.in{

		fmt.Printf("Worker %d received %c\n",
			id, n)
		w.done()
 	}
}

type worker struct {
	in chan int
	//done chan bool
	//wg *sync.WaitGroup
	done func()
}

func creatWorker(id int , wg *sync.WaitGroup) worker{
	w := worker{
		in : make(chan int),
		done: func() {
			wg.Done()
		},
	}
	go doWorker(id, w)
	return w
}

func channDemo() {
	var wg sync.WaitGroup
	var workers [10] worker
	for i := 0; i < 10; i++ {
		//创建10个channel
		workers[i] = creatWorker(i, &wg)
	}
	wg.Add(20)

	//分别给10个channel发送数据
	for i, worker := range workers{
		worker.in <- 'a' + i
		//<-workers[i].done
	}
	for i , worker := range workers{
		worker.in <- 'A' + i
		//<-workers[i].done
	}
	wg.Wait()

}

func main() {
	fmt.Println("Channel as first-class citizen")
	channDemo()

}

使用Channel实现树的遍历

#main.go

package main

import (
	"fmt"
	"awesomeProject/11-3-tree-traverse"
)

func main() {
	var root tree_11.TreeNode
	root = tree_11.TreeNode{Value:3}
	root.Left = &tree_11.TreeNode{}
	root.Right = &tree_11.TreeNode{5,nil,nil}
	root.Left.Right = tree_11.CreatNode(2)
	root.Right.Left = new(tree_11.TreeNode)


	root.Right.Left.SetValue(4)
	root.Traverse()

	nodeCount := 0
	root.TraverseFunc(func(n *tree_11.TreeNode) {
		nodeCount++
	})
	fmt.Println("Node count:", nodeCount)

	c := root.TraverseWithChannel()
	maxNode := 0
	for node := range c{
		if node.Value > maxNode {
			maxNode = node.Value
		}
	}
	fmt.Println("Max Node value:", maxNode)
}

#node.go

package tree_11

import "fmt"

type TreeNode struct {
	Value int
	Left,Right *TreeNode
}



func CreatNode(value int) *TreeNode {
	return &TreeNode{Value:value}
}

/*结构体得方法*/

func (node TreeNode) Print() {
	fmt.Println(node.Value)
}

func (node *TreeNode) SetValue(value int) {
	node.Value = value
}

func (node *TreeNode) Traverse() {
	node.TraverseFunc(func (n *TreeNode) {
		n.Print()
	})
	fmt.Println()
}

func (node *TreeNode) TraverseFunc(f func(*TreeNode)) {
	if node == nil {
		return
	}
	node.Left.TraverseFunc(f)
	f(node)
	node.Right.TraverseFunc(f)
}

func (node *TreeNode) TraverseWithChannel() chan *TreeNode {
	out := make(chan  *TreeNode)
	go func() {
		node.TraverseFunc(func(node *TreeNode) {
			out <- node
		})
		close(out)
	}()
	return out
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值