Go语言圣经-并发的非阻塞缓存详解编程语言
2023-06-13 09:20:37 时间
1.go test命令是一个按照约定和组织进行测试的程序
2.竞争检查器 go run -race 附带一个运行期对共享变量访问工具的test,出现WARNING: DATA RACE 说明有数据竞争
3.理想情况下是应该避免掉多余的工作的,称为duplicate suppression(重复抑制/避免)
4.设计并发,不重复,无阻塞 cache
1.并发: go func(){}()直接启动新的goroutine来实现
2.并发安全:使用sync.Mutex 互斥锁来实现
3.无阻塞:get之前锁定,赋值一个入口指针后立马解锁,然后进行http请求,这样不会被慢的http请求阻塞住
4.不重复:利用channel,多个并发同时写的时候,利用channel阻塞住,等第一个请求完写完后关闭channel,其他goroutine直接请求
package main import ( "fmt" "golang.org/x/net/html" "io/ioutil" "log" "net/http" "sync" "time" // 定义类型Memo type Memo struct { f Func mu sync.Mutex cache map[string]*entry type Func func(key string) (interface{}, error) type result struct { value interface{} err error type entry struct { res result ready chan struct{} // closed when res is ready func main() { //res, _ := httpGetBody("http://www.baidu.com") //fmt.Println(string(res.([]byte))) //类型断言 //初始化 m := New(httpGetBody) urls, _ := Extract("http://www.baidu.com") var n sync.WaitGroup for _, 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() //初始化Memo类型 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() e := memo.cache[key] if e == nil { e = entry{ready: make(chan struct{})} memo.cache[key] = e memo.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 //获取http get数据 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 []string visitNode := 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)
12524.html
cgo相关文章
- 并发与并行,同步和异步,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang并发编程之GoroutineEP13
- 2022-09-04:以下go语言代码输出什么?A:不能编译;B:45;C:45.2;D:45.0。 package main import ( “fmt“ )
- Go进阶训练营 – 微服务概览与治理二:微服务设计
- Go HTTP 编程 | 03 - 表单的输入与验证
- 「Go工具箱」go语言csrf库的使用方式和实现原理
- go进阶(2) -深入理解Channel实现原理
- GO进阶(5) 垃圾回收机制
- 「Go工具箱」推荐一个变量调试神器:go-spew
- 「Go工具箱」将文件大小转换成Kb、Mb、Gb就用这个库:go-humanize
- 「Go工具箱」解析http中的user-agent,就用这个包:user_agent
- 2022-12-29:nsq是go语言写的消息队列。请问k3s部署nsq,yaml如何写?
- 开心档之Go 并发
- Go语言——并发编程
- Go-包管理-go mod(一)
- Go-包管理-go clean
- Go-RESTful-创建RESTful API服务(三)
- Go语言的核心Routine-Channel详解编程语言
- 最好的6个Go语言Web框架详解编程语言
- GO语言圣经-并发获取多个URL详解编程语言
- Go语言竞态检测——检测代码在并发环境下可能出现的问题
- Go语言分布式id生成器
- Go语言环境配置:在 Linux 下实现(go环境搭建linux)
- 关键字在SQL Server中利用GO关键字实现更优化的操作(sqlserver中go)
- 徒手用Go编写Redis迈向新技术世界的旅程(徒手用go写个redis)
- Go语言操作Oracle轻松实现数据库编程(go语言访问oracle)
- 程序Go语言调用Oracle数据库驱动程序指南(go oracle驱动)
- Go语言并发技术详解