Go 指南 Goroutine


Go 指南的Concurrency

这里主要总结Go指南中的

官方地址


提示:以下是我对官方指南的摘要

一、基本使用

Go routine

在func前面加go就会生成一个go routine

func RunGoroutine() {
	go func() {
		say("Hello, World")
	}()
}

func say(s string)  {
	fmt.Println(s)
}

Channels

channels用于两个routine之间的通信的,这里利用两个channels同时计算数组元素的和

func sum(s []int, c chan int)  {
	sum := 0
	for _, v := range s{
		sum += v
	}
	c <- sum
}

func CalculateSum() {
	s := []int{7, 2, 8, -9, 4, 0}
	c := make(chan int)
	go sum(s[:len(s)/2], c)
	go sum(s[len(s)/2:], c)
	x, y := <- c, <- c
	fmt.Println(x, y, x+y)
}

Buffered Channels

就是buffer满了才开始通信
原来如果没有buffer,如下的Code是不能运行的,因为一开始channel只有1的容量,当消息发出去的时候需要马上接,否则满了就不能在接受下一个传过来的值了

func Buffer() {
	ch := make(chan int)
	ch <- 1
	ch <- 2
	fmt.Println(<-ch)
	fmt.Println(<-ch)
}

加上buffer就可以运行了,因为有了数量为2个的缓冲

func Buffer() {
	ch := make(chan int, 2)
	ch <- 1
	ch <- 2
	fmt.Println(<-ch)
	fmt.Println(<-ch)
}

Range and Close

发送方如果需要关闭channel有2种方法

1. v, ok := <-ch
2. for i := range c

func fibonacci(n int, c chan int) {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		c <- x
		x, y = y, x+y
	}
	close(c)
}

func main() {
	c := make(chan int, 10)
	go fibonacci(cap(c), c)
	for i := range c {
		fmt.Println(i)
	}
}

map的线程安全

在Go中的map并不是线程安全的,或者说在使用Goroutine的时候会出现 fatal error: concurrent map read and map write
解决方法是:
使用 sync.Mutex

type Counter struct {
	v map[string] int
	Lock sync.Mutex
}

func (c *Counter) Inc(key string)  {
	c.Lock.Lock()
	defer c.Lock.Unlock()
	c.v[key]++
}

func (c *Counter) Value(key string) int{
	c.Lock.Lock()
	defer c.Lock.Unlock()
	return c.v[key]
}

func RunInc() {
	c := Counter{v: map[string]int{}}
	for i := 0; i < 1000; i++ {
		go c.Inc("somekey")
	}
	time.Sleep(time.Second)
	fmt.Println(c.Value("somekey"))
}

二、练习 Equivalent Binary Trees

题目如下:
Exercise: 寻找等价的BST
在这里插入图片描述
需要实现
Walk 将所有的值从 tree 发送到 channel ch。
Same 检测树 t1 和 t2 是否含有相同的值。

我的实现如下:

- Walk 主要是中序遍历,把值传给channel
- Same 主要是处理传过来的值,最对比

func Walk(t *tree.Tree, ch chan int) {
	if t == nil {
		return
	}
	Walk(t.Left, ch)
	ch <- t.Value
	Walk(t.Right, ch)
}
func Same(t1, t2 *tree.Tree) bool {
	ch1 := make(chan int)
	ch2 := make(chan int)
	
	go func() {
		Walk(t1, ch1)
		close(ch1)
	}()

	go func() {
		Walk(t2, ch2)
		close(ch2)
	}()

	for {
		x, ok := <-ch1
		if !ok {
			break
		}
		y, ok := <-ch2
		if !ok {
			break
		}
		if x != y {
			return false
		}
		fmt.Println("x and y are ", x, y)
	}
	return true
}

三、练习web crawler

我的版本, 主要是通过map做数据的存储,通过Mutex保证数据的一直性

type UrlMap struct {
	m   map[string]int
	mux sync.Mutex
}

func (urlMap *UrlMap) getUrl(url string) int {
	urlMap.mux.Lock()
	defer urlMap.mux.Unlock()
	return urlMap.m[url]
}

func (urlMap *UrlMap) setUrl(url string) {
	urlMap.mux.Lock()
	defer urlMap.mux.Unlock()
	urlMap.m[url]++
}

// Crawl uses fetcher to recursively crawl
// pages starting with url, to a maximum of depth.
func Crawl(url string, depth int, fetcher Fetcher, urlMap *UrlMap) {

	if depth <= 0 {
		return
	}

	if urlMap.getUrl(url) > 1 {
		return
	}

	body, urls, err := fetcher.Fetch(url)

	if err != nil {
		fmt.Println(err)
		return
	}

	var newUrls []string
	for _, u := range urls {
		if urlMap.getUrl(u) == 0 {
			urlMap.setUrl(u)
			newUrls = append(newUrls, u)
		}
	}

	fmt.Printf("found: %s %q\n", urls, body)
	for _, u := range newUrls {
		go Crawl(u, depth-1, fetcher, urlMap)
	}

	return
}

func RunCrawl() {
	urlMap := UrlMap{m: map[string]int{"https://golang.org/": 1}}
	Crawl("https://golang.org/", 4, fetcher, &urlMap)
	time.Sleep(100 * time.Millisecond)
}

总结

Goroutine的线程需要有好的设计才能更好地发挥起作用,这里的知识还是很多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值