another package of fetchers

This commit is contained in:
Jian Han 2018-01-06 15:55:04 +10:00
parent 54a3ffe76b
commit dc000eb40f
3 changed files with 102 additions and 10 deletions

View File

@ -9,6 +9,14 @@ import (
"github.com/davecgh/go-spew/spew"
)
// https://medium.com/capital-one-developers/buffered-channels-in-go-what-are-they-good-for-43703871828
// One common pattern for goroutines is fan-out. When you want to apply the same data to multiple algorithms,
// you can launch a goroutine for each subtask, and then gather the data back in when they are done.
// For example, you might want to process the same data via multiple scoring algorithms and return back
// all of the scores or pull data from multiple microservices to compose a single page. A buffered channel is an
// ideal way to gather the data back from your subtasks.
func RunDivideAndConquer() {
type in struct {
a int

View File

@ -1 +1,92 @@
package fetchers
import (
"fmt"
"time"
"github.com/davecgh/go-spew/spew"
)
type Fetcher interface {
Fetch(url string) (string, error)
GetName() string
}
type GoogleFetcher struct {
Name string
}
func (g *GoogleFetcher) Fetch(url string) (string, error) {
return fmt.Sprintf("%s is fetching %s", g.Name, url), nil
}
func (g *GoogleFetcher) GetName() string {
return g.Name
}
func NewGoogleFetcher(name string) *GoogleFetcher {
return &GoogleFetcher{Name: name}
}
type BingFetcher struct {
Name string
}
func (b *BingFetcher) Fetch(url string) (string, error) {
return fmt.Sprintf("%s is fetching %s", b.Name, url), nil
}
func (b *BingFetcher) GetName() string {
return b.Name
}
func NewBingFetcher(name string) *BingFetcher {
return &BingFetcher{Name: name}
}
type DuckDuckGoFetcher struct {
Name string
}
func (d *DuckDuckGoFetcher) Fetch(url string) (string, error) {
return fmt.Sprintf("%s is fetching %s", d.Name, url), nil
}
func (d *DuckDuckGoFetcher) GetName() string {
return d.Name
}
func NewDuckDuckGoFetcherFetcher(name string) *DuckDuckGoFetcher {
return &DuckDuckGoFetcher{Name: name}
}
func FetchResults(url string, fetchers []Fetcher, timeout time.Duration) ([]string, []error) {
chStr := make(chan string)
chErr := make(chan error)
for _, f := range fetchers {
go func(f Fetcher) {
s, err := f.Fetch(url)
if err != nil {
chErr <- err
} else {
chStr <- s
}
}(f)
}
stringResults := []string{}
errorResults := []error{}
for range fetchers {
select {
case s := <-chStr:
stringResults = append(stringResults, s)
case e := <-chErr:
errorResults = append(errorResults, e)
}
}
return stringResults, errorResults
}
func RunFetchers() {
fetchers := []Fetcher{NewGoogleFetcher("Google"), NewGoogleFetcher("Bing"), NewGoogleFetcher("Duck Duck Go")}
r, e := FetchResults("http://www.abc.com", fetchers, time.Millisecond*100)
spew.Dump(r, e)
}

View File

@ -1,15 +1,8 @@
package main
import "github.com/jianhan/go-patterns/concurrency/subtasks/divide_and_conquer"
// https://medium.com/capital-one-developers/buffered-channels-in-go-what-are-they-good-for-43703871828
// One common pattern for goroutines is fan-out. When you want to apply the same data to multiple algorithms,
// you can launch a goroutine for each subtask, and then gather the data back in when they are done.
// For example, you might want to process the same data via multiple scoring algorithms and return back
// all of the scores or pull data from multiple microservices to compose a single page. A buffered channel is an
// ideal way to gather the data back from your subtasks.
import "github.com/jianhan/go-patterns/concurrency/subtasks/fetchers"
func main() {
divide_and_conquer.RunDivideAndConquer()
// divide_and_conquer.RunDivideAndConquer()
fetchers.RunFetchers()
}