东莞专业的单位网站建设,做平面设计什么素材网站好使,学习网站制作,青岛微信网站建设一、goroutine 和 通道 在Go语言中#xff0c;每一个并发执行的活动成为goroutine。通道则是每一个goroutine之间传递消息的工具。 1、Goroutine
在一个Go程序中#xff0c;只有一个主Goroutine来调用main函数。生成新的goroutine也十分简单#xff0c;例如有一个函数…一、goroutine 和 通道 在Go语言中每一个并发执行的活动成为goroutine。通道则是每一个goroutine之间传递消息的工具。 1、Goroutine
在一个Go程序中只有一个主Goroutine来调用main函数。生成新的goroutine也十分简单例如有一个函数f(), 只需在其前面加上go关键字即可将其作为并发程序执行。 例
package mainimport (fmttime
)func main() {n : 5//开启goroutinego f(n)for i : 0; i n; i {fmt.Println(I am goroutine main())time.Sleep(50 * time.Millisecond)}
}func f(n int) {for i : 0; i n; i {fmt.Println(I am goroutine f())time.Sleep(50 * time.Millisecond)}
}// sout:
// I am goroutine main()
// I am goroutine f()
// I am goroutine f()
// I am goroutine main()
// I am goroutine main()
// I am goroutine f()
// I am goroutine f()
// I am goroutine main()
// I am goroutine main()
// I am goroutine f()虽然Go语言实现并发十分方便但是如何实现goroutine之间的通信以及保证并发的安全性依然是一件有挑战的事。
2、通道(chan)
通道是goroutine之间的连接让特定的值在各个goroutine之间传递。 使用make函数创建一个通道ch : make(chan type, cap). type为ch传递值的类型cap为通道的大小同时能容纳多少值type可以为任意类型。 通道对应操作都存在阻塞
发送 ( c h − x ch-x ch−x) x为对应类型的变量ch为通道。ch满了会存在阻塞接受( x − c h x-ch x−ch)x为对应类型的变量ch为通道。ch空了会存在阻塞关闭通道close(ch)ch发送操作被禁止接受操作被释放
无缓冲通道 通道只有一个元素接受方和发送方会相互阻塞。 管道 通道有多个chan元素用来连接不同的goroutine一个chan的输入是另一个chan的输入。 单向通道类型 类型( c h a n − i n t chan-int chan−int)为只能发送的通道类型( − c h a n i n t -chan int −chanint)为只能接收的int类型通道。 缓冲通道 有一个元素队列一个cap大于1的通道类型。
注意细节
chan变量默认值为nil使用’时若二者是同一通道数据的引用时返回true。若关闭后还有写操作会发生宕机panic读取其零值故可将其作为开关使用。操作 x,ok : -ch x为读取的值ok为bool值当ch被close时会返回false故可以使用range来获取ch的值直到ch被close。select开关操作关闭某一服务利用select捕获通道关闭的信息从而关闭对应的服务。 例 done : make(chan struct{})go func() {os.Stdin.Read(make([]byte, 1))close(done)}()loop:for {select {//捕获是否关闭。case -done:fmt.Println(program end!)break loopdefault:fmt.Println(program runing!)}time.Sleep(1 * time.Second)}一个爬虫案例使用bfs方式爬取一个网页的所有url
package gorunimport (fmtlognet/httpgolang.org/x/net/html
)func Catch() {//通道用来在goroutine之间传递结果worklist : make(chan []string)//计数器用来判断结束状态关闭goroutinecnt : 0go func() {worklist - []string{http://bm.scs.gov.cn/pp/gkweb/core/web/ui/business/person/person_home.html}}()cnt//标记已遍历的url防止重复的url被读取seen : make(map[string]bool)for ; cnt 0; cnt-- {list : -worklistfor _, link : range list {if !seen[link] {seen[link] truecnt//慢函数用新的goroutine执行提高效率。go func(link string) {//该处会不停地生成新的goroutineworklist - crawl(link)}(link)}}}
}
//chan变量利用其阻塞的特性用于控制新增goroutine的数量
var token make(chan struct{}, 20)// 在生成goroutine时做限制控制生成的goroutine的数量
func crawl(url string) []string {fmt.Println(url)//获取token - struct{}{}list, err : extract(url)//释放defer func() {-token}()if err ! nil {log.Println(err)}return list
}//分析网页中的html文件搜索其中的url
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(parse %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}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)}
}