Skip to content

Instantly share code, notes, and snippets.

@jordanorelli
Created November 21, 2021 12:52
Show Gist options
  • Save jordanorelli/5debfbf8dfa0e8c7fa4dfcb3b08f9478 to your computer and use it in GitHub Desktop.
Save jordanorelli/5debfbf8dfa0e8c7fa4dfcb3b08f9478 to your computer and use it in GitHub Desktop.
generic channel composition in Go
package main
import (
"errors"
"fmt"
"math/rand"
"time"
)
type code int
func (c code) Error() string { return fmt.Sprintf("error code %d", int(c)) }
func work() (int, error) {
luck := rand.Intn(100)
if luck == 0 {
time.Sleep(30 * time.Second)
return 0, errors.New("timed out")
}
delay := time.Duration(rand.Intn(3000)) * time.Millisecond
time.Sleep(delay)
if luck < 6 {
return 0, code(luck)
}
return rand.Intn(100), nil
}
type maybe[T any] struct {
value T
err error
}
func (m maybe[T]) isError() bool { return m.err != nil }
func join[T any](left, right <-chan T) <-chan T {
if left == nil {
return right
}
if right == nil {
return left
}
c := make(chan T)
go func() {
for left != nil || right != nil {
select {
case v, ok := <-left:
if !ok {
left = nil
} else {
c <- v
}
case v, ok := <-right:
if !ok {
right = nil
} else {
c <- v
}
}
}
close(c)
}()
return c
}
func worker() <-chan maybe[int] {
c := make(chan maybe[int])
n := rand.Intn(3)
go func() {
for i := 0; i < n; i++ {
v, err := work()
c <- maybe[int]{v, err}
}
close(c)
}()
return c
}
func main() {
numWorkers := 10
var c <-chan maybe[int]
for i := 0; i < numWorkers; i++ {
c = join(c, worker())
}
for m := range c {
fmt.Println(m)
}
}
func init() {
rand.Seed(time.Now().UnixNano())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment