ruk·si

Go
Take Best Pattern

Updated at 2013-12-03 23:27

Fan-in. Use the channel which is ready to talk first by merging multiple channels.

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func boring(msg string) <-chan string {
    c := make(chan string)
    go func() {
        for i := 0; ; i++ {
            c <- fmt.Sprintf("%s %d", msg, i)
            time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond)
        }
    }()
    return c
}

func fanIn(input1, input2 <-chan string) <-chan string {
    c := make(chan string)
    go func() {
        for {
            select {
            case s := <-input1:
                c <- s
            case s := <-input2:
                c <- s
            }
        }
    }()
    return c
}

func main() {
    c := fanIn(boring("Joe"), boring("Ann"))
    for i := 0; i < 10; i++ {
        fmt.Println(<-c)
    }
    fmt.Println("You're both boring; I'm leaving.")
}

Use only the first passed value from a channel.

package main

import (
    "fmt"
    "net/http"
    "sync"
)

type response struct {
    resp *http.Response
    url  string
}

func get(url string, r chan<- response, wg *sync.WaitGroup) {
    defer wg.Done()
    resp, err := http.Get(url)
    if err == nil {
        return
    }
    if resp == nil {
        return
    }
    select {
    case r <- response{resp, url}:
    default:
    }
}

// if the channels is not closed, following responses will
// be left to waiting for someone to read the channel
func closeAfterAllTries(r chan response, wg *sync.WaitGroup) {
    wg.Wait()
    close(r)
}

func main() {
    takeFirst := make(chan response)
    urls := []string{
        "http://code.jquery.com/jquery-1.9.1.min.js",
        "http://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js",
        "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js",
        "http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js",
    }
    wg := sync.WaitGroup{}
    for _, url := range urls {
        wg.Add(1)
        go get(url, takeFirst, &wg)
    }
    go closeAfterAllTries(takeFirst, &wg)
    r := <-takeFirst
    fmt.Println(r) // can be nil struct if all fail
}