1. Go测试工具是基于约定和规范进行测试的命令。
2. 使用`go run -race`命令可以检测共享变量访问中的数据竞争情况。该工具会显示WARNING: DATA RACE。
3. 理想情况下,应该避免不必要的工作,这被称为Duplicate Suppression。
4. 构建并发、无重复、无阻塞的缓存:
通过以下方式实现并发:
1. 使用`go func() {}()`启动新的goroutine。
2.确保并发安全:使用sync.Mutex互斥锁。
3.优化HTTP请求bole:
在获取之前对缓存位置加锁定,并为入口指针分配存όρ后立即解锁。这样可以避免被慢的HTTP请求阻塞。
4. 去重存储:
使用渠道机制,批量处理请求。在第一个请求完成后关闭渠道,这样其他goroutine可以直接调用。
package main
import ("fmt""golang.org/x/net/html""io/ioutil""log""net/http""sync""time")
type Memo struct {Func Funcmu sync.Mutexcache map[string]*entry}
type result struct {value interface{}err error}
type entry struct {res resultready chan struct{} // Closed when res is ready}
func main() {// Initialize Memom := New(httpGetBody)urls, _ := Extract("http://www.baidu.com")
var n sync.WaitGroupfor _, url := range urls { n.Add(1) go func(url string) { fmt.Println(url) start := time.Now() value, err := m.Get(url) if err != nil { log.Print(err) } if value != nil { fmt.Printf("%s, %s, %d bytes\n", url, time.Since(start), len(value.([]byte))) } n.Done() }(url)}n.Wait()
}
func New(f Func) *Memo {return &Memo{f: f,cache: make(map[string]*entry),}}
func (memo *Memo) Get(key string) (interface{}, error) {memo.mu.Lock()if e := memo.cache[key]; e == nil {e = &entry{ready: make(chan struct{})}memo.cache[key] = ememo.mu.Unlock()e.res.value, e.res.err = memo.f(key)close(e.ready)} else {memo.mu.Unlock()<-e.ready}return e.res.value, e.res.err}
func httpGetBody(url string) (interface{}, error) {resp, err := http.Get(url)if err != nil {return nil, err}defer resp.Body.Close()return ioutil.ReadAll(resp.Body)}
func Extract(url string) ([]string, error) {resp, err := http.Get(url)if err != nil {return nil, err}if resp.StatusCode != http.StatusOK {resp.Body.Close()return nil, fmt.Errorf("getting %s: %s", url, resp.Status)}doc, err := html.Parse(resp.Body)resp.Body.Close()if err != nil {return nil, fmt.Errorf("parsing %s as HTML: %v", url, err)}var links []stringvisitNode := func(n *html.Node) {if n.Type == html.ElementNode && n.Data == "a" {for _, a := range n.Attr {if a.Key != "href" {continue}link, err := resp.Request.URL.Parse(a.Val)if err != nil {continue // Ignore bad URLs}links = append(links, link.String())}}}forEachNode(doc, visitNode, nil)return links, nil}
func forEachNode(n *html.Node, pre, post func(n *html.Node)) {if pre != nil {pre(n)}for c := n.FirstChild; c != nil; c = c.NextSibling {forEachNode(c, pre, post)}if post != nil {post(n)}}