golang notes(4)

1, Execise: Equivalent Binary Trees

package main

import (
	"fmt"
	"golang.org/x/tour/tree"
)

func Walk(t *tree.Tree, ch chan int) {
	if t != nil {
		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 Walk(t1, ch1)
	go Walk(t2, ch2)

	for i := 0; i < 10; i++ {
		if <-ch1 != <-ch2 {
			return false
		}
	}

	return true
}

func main() {
	t1 := tree.New(1)
	t2 := tree.New(2)

	fmt.Printf("t1 == t1? %v\n", Same(t1, t1))
	fmt.Printf("t1 == t2? %v\n", Same(t1, t2))
}

 

2, Execise: Web Crawler

Solution #1: use channel to synchronize goroutines 

  • <cache *Cache> is used to avoid URL duplication
  • <ch chan int> is used to wait for end of a goroutine
func Crawl(url string, depth int, fetcher Fetcher, cache *Cache, ch chan int) {
	if depth <= 0 || cache.urls[url] {
		ch <- 1
		return
	}

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

	cache.mu.Lock()
	cache.urls[url] = true
	cache.mu.Unlock()

	if err != nil {
		fmt.Println(err)
		ch <- 1
		return
	}

	fmt.Printf("Found: %s %q\n", url, body)

	subch := make(chan int, len(urls))
	for _, u := range urls {
		go Crawl(u, depth-1, fetcher, cache, subch)
		<-subch
	}

	ch <- 1
	return
}

type Cache struct {
	mu sync.Mutex
	urls map[string]bool
}

func main() {
	cache := Cache{urls: make(map[string]bool)}
	ch := make(chan int)
	go Crawl("https://golang.org/", 4, fetcher, &cache, ch)
	<-ch
}

Output looks like:

Found: https://golang.org/ "The Go Programming Language"
not found: https://golang.org/cmd/
Found: https://golang.org/pkg/ "Packages"
Found: https://golang.org/pkg/os/ "Package os"
Found: https://golang.org/pkg/fmt/ "Package fmt"

Solution #2: use sync.WaitGroup to synchronize goroutines

refer to: 

https://stackoverflow.com/questions/12224962/exercise-web-crawler-concurrency-not-working

https://www.dyxmq.cn/program/code/golang/waitgroup-in-golang.html

func Crawl(url string, depth int, fetcher Fetcher, cache *Cache, wg *sync.WaitGroup) {
	defer wg.Done()

	if depth <= 0 || cache.urls[url] {
		return
	}

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

	cache.mu.Lock()
	cache.urls[url] = true
	cache.mu.Unlock()

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

	fmt.Printf("Found: %s %q\n", url, body)

	for _, u := range urls {
		wg.Add(1)
		go Crawl(u, depth-1, fetcher, cache, wg)
	}

	return
}

type Cache struct {
	mu sync.Mutex
	urls map[string]bool
}

func main() {
	cache := Cache{urls: make(map[string]bool)}
	wg := &sync.WaitGroup{}
	wg.Add(1)
	go Crawl("https://golang.org/", 4, fetcher, &cache, wg)
	wg.Wait()
}

 

The journey into 'A Tour of Go' ends here!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值