[web result for "golang", video result for "golang", image result for "golang"]
66.194887ms
Search with Timeout
We can make our search a bit more robust by introducing timeout because there's a chance that some results won't come back for a while and we don't want to wait for it.
func google(query string) (results []string) {
ch := make(chan string)
go func() {
ch <- web(query)
}()
go func() {
ch <- image(query)
}()
go func() {
ch <- video(query)
}()
timeout := time.After(80 * time.Millisecond)
for i := 0; i < 3; i++ {
select {
case r := <-ch:
results = append(results, r)
case <-timeout:
fmt.Println("timed out")
return results
}
}
return results
}
Distributed Search
Suppose we can make requests to make multiple slave/replica servers and only return searches that complete in under 80 milliseconds.
func multisearch(query string, replicas ...search) string {
ch := make(chan string)
searchReplica := func(i int) {
ch <- replicas[i](query)
}
for i := range replicas {
go searchReplica(i)
}
// As soon as one of the replicas returns a result, return immediately.
return <-ch
}
Now we can make requests to multiple slave servers.
var (
web1 = getSearch("web")
web2 = getSearch("web")
image1 = getSearch("image")
image2 = getSearch("image")
video1 = getSearch("video")
video2 = getSearch("video")
)
func google(query string) (results []string) {
ch := make(chan string)
go func() {
ch <- multisearch(query, web1, web2)
}()
go func() {
ch <- multisearch(query, image1, image2)
}()
go func() {
ch <- multisearch(query, video1, video2)
}()
timeout := time.After(80 * time.Millisecond)
for i := 0; i < 3; i++ {
select {
case r := <-ch:
results = append(results, r)
case <-timeout:
fmt.Println("timed out")
return results
}
}
return results
}