开心一刻
虽然经常被老婆打,但苍天可鉴,老婆并非是不讲理的人。每次打之前,都会征求我的同意,我说不同意,她就打到我同意。
题目介绍有三个需要并发执行的函数,三个函数会返回同一类型的值,且三个函数执行时间在2ms到10ms之间不等,而主程序要求在5ms内返回结果,若5ms内没有执行完毕,则强制返回结果,这个时候某个函数可能还没有返回因此没有值。下面是我的做法,纯属个人写法。
并发编程这里的三个函数分别是:
func searchText(query string) Result
func searchImage(query string) Result
func searchVideo(query string) Result
三个函数除了函数名称不同,参数和返回值均相同,函数内部就是具体的调用逻辑了,因为这里不关心,所以统一使用time.Sleep方法来模拟函数的执行时间。
package main
import (
"context"
"fmt"
"time"
)
type Result string
func searchText(query string) Result {
time.Sleep(5*time.Millisecond)
return "text"
}
func searchImage(query string) Result {
time.Sleep(2*time.Millisecond)
return "image"
}
func searchVideo(query string) Result {
time.Sleep(4*time.Millisecond)
return "video"
}
// Search是其中的主体代码,ctx是Context类型的对象,用来超时退出
func Search(ctx context.Context, query string) []Result {
var (
result []Result
// ch被用来接收返回值,ch属于同步channel,如果二个函数都返回,那么在第一个返回值被读取之前,第二个将会被阻塞。
ch = make(chan Result)
)
// 因为这里用的是匿名函数,因此ch可以直接使用,如果不用匿名函数,可以将ch作为参数传递,能起到相同的效果。
go func() {
ch <- searchText(query)
}()
go func() {
ch <- searchImage(query)
}()
go func() {
ch <- searchVideo(query)
}()
// 使用context包中的WithTimeout方法生成一个定时器,因为这里固定为最多5ms,所以第二个返回值省略了
ctx, _ = context.WithTimeout(ctx, 5 * time.Millisecond)
for {
select {
// 超过5ms,就会退出
case <- ctx.Done():
fmt.Println("时间到")
return result
// 某个函数返回后,就会触发,然后将结果添加到result中
case val := <- ch:
result = append(result, val)
// 可以实现提前退出,因为如果三个函数均在5ms内返回,那么该程序不必非要等待5ms才退出
default:
if len(result) == 3 {
fmt.Println("执行完毕")
return result
}
}
}
}
func main() {
res := Search(context.Background(), "hello")
fmt.Println(res)
}
程序执行后,多次执行会看到不同的结果。
文中都是我个人的理解,如有错误的地方欢迎下方评论告诉我,我及时更正,大家共同进步