协程,解决了高并发的问题。创建一个协程大约只耗费5KB左右空间。
代码为例,实战学习:
package main
import (
"fmt"
"net/http"
)
func main() {
//创建一个切片,存储五个网站
links := []string{
"https://www.zhihu.com/",
"https://www.baidu.com/",
"https://https://www.sdfasdfa.com/", //无效网站
"https://www.huawei.com",
"https://www.1688.com/",
}
//循环遍历切片
for _, link := range links {
GetLink(link)
}
fmt.Println("结束")
}
//判断传入网站是否可以连接上
func GetLink(link string) {
_, err := http.Get(link)
if err != nil {
fmt.Println("网站", link, "连接失败...")
return
}
fmt.Println("网站", link, "连接成功...")
}
运行,输出结果为:
GOROOT=C:Go #gosetup
GOPATH=E:Project #gosetup
C:Gobingo.exe build -o E:Projectbingo_build_main_go.exe E:Projectsrchelloworldmain.go #gosetup
E:Projectbingo_build_main_go.exe #gosetup
网站 https://www.zhihu.com/ 连接成功...
网站 https://www.baidu.com/ 连接成功...
网站 https://https://www.sdfasdfa.com/ 连接失败...
网站 https://www.huawei.com 连接成功...
网站 https://www.1688.com/ 连接成功...
结束
Process finished with exit code 0
根据输出结果可以看出,网站都是顺序输出的,逻辑图1如下
协程的定义方式:
那接下来我们引入协程的用法:在GetLink(link)前面添加 go
package main
import (
"fmt"
"net/http"
)
func main() {
//创建一个切片,存储五个网站
links := []string{
"https://www.zhihu.com/",
"https://www.baidu.com/",
"https://https://www.sdfasdfa.com/", //无效网站
"https://www.huawei.com",
"https://www.1688.com/",
}
//循环遍历切片
for _, link := range links {
go GetLink(link)
}
fmt.Println("结束")
}
//判断传入网站是否可以连接上
func GetLink(link string) {
_, err := http.Get(link)
if err != nil {
fmt.Println("网站", link, "连接失败...")
return
}
fmt.Println("网站", link, "连接成功...")
}
运行,输出结果为:
GOROOT=C:Go #gosetup
GOPATH=E:Project #gosetup
C:Gobingo.exe build -o E:Projectbingo_build_main_go.exe E:Projectsrchelloworldmain.go #gosetup
E:Projectbingo_build_main_go.exe #gosetup
结束
Process finished with exit code 0
额,,,为什么添加了Go关键字以后,不输出网站了呢?
因为 goroutine 以非阻塞的方式执行,它们会随着主线程(Main())的结束而消亡,所以程序输出字符串 "结束" 就退出了
怎么办呢?
我们在Main()函数的最后添加一个等待,等待其他协程都执行完毕再结束主线程就ok了
代码如下:
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
//创建一个切片,存储五个网站
links := []string{
"https://www.zhihu.com/",
"https://www.baidu.com/",
"https://https://www.sdfasdfa.com/", //无效网站
"https://www.huawei.com",
"https://www.1688.com/",
}
//循环遍历切片
for _, link := range links {
go GetLink(link)
}
//等待10s
time.Sleep(10*time.Second)
fmt.Println("结束")
}
//判断传入网站是否可以连接上
func GetLink(link string) {
_, err := http.Get(link)
if err != nil {
fmt.Println("网站", link, "连接失败...")
return
}
fmt.Println("网站", link, "连接成功...")
}
运行,输出结果为
GOROOT=C:Go #gosetup
GOPATH=E:Project #gosetup
C:Gobingo.exe build -o E:Projectbingo_build_main_go.exe E:Projectsrchelloworldmain.go #gosetup
E:Projectbingo_build_main_go.exe #gosetup
网站 https://www.huawei.com 连接成功...
网站 https://www.1688.com/ 连接成功...
网站 https://www.baidu.com/ 连接成功...
网站 https://www.zhihu.com/ 连接成功...
网站 https://https://www.sdfasdfa.com/ 连接失败...
结束
Process finished with exit code 0
ok,这次可以打印出网站了,而且打印出来的网站不是按照定义时的顺序打印的。
但是我们实际上不知道其他协程需要执行多长时间,所以这种方式讲道理的话,有点拉胯!!!
为了高端一点解决上述问题,为了显得不是很low,那么,我们引入通道(Channel)的概念
什么是通道(Channel)?
通道就是实现协程之前的通信。
定义方式为:
那我们接下来就将通道应用到代码中:
package main
import (
"fmt"
"net/http"
)
func main() {
//创建一个切片,存储五个网站
links := []string{
"https://www.zhihu.com/",
"https://www.baidu.com/",
"https://https://www.sdfasdfa.com/", //无效网站
"https://www.huawei.com",
"https://www.1688.com/",
}
//定义一个通道
c := make(chan string)
//循环遍历切片
for _, link := range links {
go GetLink(link, c)
}
//接收消息
for i := 0; i < len(links); i++ {
<-c
}
fmt.Println("结束")
}
//判断传入网站是否可以连接上
func GetLink(link string, c chan string) {
_, err := http.Get(link)
if err != nil {
fmt.Println("网站", link, "连接失败...")
//代表从这个协程通道中返回一个string值到main协程(主协程)中
c <- "连接失败..."
return
}
fmt.Println("网站", link, "连接成功...")
c <- "连接成功..."
}
运行,输出结果为
GOROOT=C:Go #gosetup
GOPATH=E:Project #gosetup
C:Gobingo.exe build -o E:Projectbingo_build_main_go.exe E:Projectsrchelloworldmain.go #gosetup
E:Projectbingo_build_main_go.exe #gosetup
网站 https://www.1688.com/ 连接成功...
网站 https://www.huawei.com 连接成功...
网站 https://www.baidu.com/ 连接成功...
网站 https://www.zhihu.com/ 连接成功...
网站 https://https://www.sdfasdfa.com/ 连接失败...
结束
Process finished with exit code
这种通道的方法呢,有一个特点:
就是有多少消息传递过来(c <- "连接成功..." or c <- "连接失败...") 就得接收多少消息(<-c)