GO语言相对于其他语言的最高特点就是其高并发性。通过go就可以实现一个函数的并发操作 下面用一个例子来解释说明
package main
import (
"fmt"
"math/rand"
"time"
)
type Result string
type Search func(query string) Result
var (
Web = fakeSearch("web")
Image = fakeSearch("image")
Video = fakeSearch("video")
)
func fakeSearch(kind string) Search {
return func(query string) Result {
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) // 将搜索时间更改为随机值
return Result(fmt.Sprintf("%s result for %q\n", kind, query))
}
}
func Google(query string) []Result {
c := make(chan Result)
go func() {
c <- Web(query)
}()
go func() {
c <- Image(query)
}()
go func() {
c <- Video(query)
}()
var results []Result
// 在这里,timeout 会在 50 毫秒后接收到管道传来的信息
timeout := time.After(50 * time.Millisecond)
for i := 0; i < 3; i++ {
select {
case r := <-c:
results = append(results, r)
case <-timeout: // 在 timeout 接收到信息后,将会结束搜索,并将结果直接返回
fmt.Println("timeout")
return results
}
}
return results
}
func main() {
rand.Seed(time.Now().UnixNano())
start := time.Now()
results := Google("golang")
elapsed := time.Since(start)
fmt.Println(results)
fmt.Println(elapsed)
}
这个代码是来自于一个大佬的对于协程,管道以及select用法的文章 原链接:Golang 并发编程实战——协程、管道、select用法 - 掘金 (juejin.cn) 下面说一下我自己对于这个代码的理解。 因为对于三个函数的并发操作无法控制其优先级,所以将其全部存入到自定义的C通道中。
var (
Web = fakeSearch("web")
Image = fakeSearch("image")
Video = fakeSearch("video")
)
对于这个三个参数的返回值是 Search类型,而 Search是我们通过type定义的一个带有参数返回值为Result的函数。其实就是一个字符串类型,因为我们通过type将其定义为了string类型。所以上面这三个参数实际上就是一个含有string类型的参数且返回值也为string的函数。 这也就是为什么下面这函数的返回值为
func fakeSearch(kind string) Search {
return func(query string) Result {
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) // 将搜索时间更改为随机值
return Result(fmt.Sprintf("%s result for %q\n", kind, query))
}
}
web result for "golang"
video result for "golang"
image result for "golang"
但是上面这个代码的运行结果不一定是这个,因为我们通过了时间函数对这个搜索进行了时间的随机性。 而我们在
// 在这里,timeout 会在 50 毫秒后接收到管道传来的信息
timeout := time.After(50 * time.Millisecond)
for i := 0; i < 3; i++ {
select {
case r := <-c:
results = append(results, r)
case <-timeout: // 在 timeout 接收到信息后,将会结束搜索,并将结果直接返回
fmt.Println("timeout")
return results
}
}
这个地方对通道进行了一个设定,如果时间小于50ms则将其结果返回到通道C中,如果超过了50ms就显示timeout同时return results字符串数组返回。 最终在屏幕上显示的结果每一次也会不同,因为我们通过
rand.Seed(time.Now().UnixNano())
保证了我们的随机数种子不同。最后的结果可能为
[
web result for "golang"
video result for "golang"
image result for "golang"
]
33.1508ms
也有可能为
timeout
[
video result for "golang"
web result for "golang"
]
63.5574ms
只有2个结果剩下一个超过了50ms没有传入通道,等等情况。