Skip to content

Instantly share code, notes, and snippets.

@StevenACoffman
Last active January 27, 2023 02:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save StevenACoffman/af81062bfe63629dd4a0c7c0bfe12599 to your computer and use it in GitHub Desktop.
Save StevenACoffman/af81062bfe63629dd4a0c7c0bfe12599 to your computer and use it in GitHub Desktop.
Golang Promises and Concurrency patterns
package main
import (
"context"
"fmt"
"math/rand"
"time"
"golang.org/x/sync/errgroup"
)
func one(ctx context.Context) int32 {
// Simulate a workload.
time.Sleep(time.Millisecond * time.Duration(rand.Int63n(2000)))
if ctx.Err() != nil {
// real workloads this would be a check for context cancellation deep
// in the http library or whatever; and would do a select to early-exit
return -1
}
return 1
}
func two(ctx context.Context) int32 {
// Simulate a workload.
time.Sleep(time.Millisecond * time.Duration(rand.Int63n(1000)))
time.Sleep(time.Millisecond * time.Duration(rand.Int63n(1000)))
if ctx.Err() != nil {
// real workloads this would be a check for context cancellation deep
// in the http library or whatever; and would do a select to early-exit
return -1
}
return 2
}
func all() {
g, ctx := errgroup.WithContext(context.Background())
var oneResult int32
var twoResult int32
g.Go(func() error {
oneResult = one(ctx)
return nil
})
g.Go(func() error {
twoResult = two(ctx)
return nil
})
g.Wait()
fmt.Println(oneResult, twoResult)
}
func race() {
g, ctx := errgroup.WithContext(context.Background())
var oneResult int32
var twoResult int32
g.Go(func() error {
oneResult = one(ctx)
return fmt.Errorf("this will cancel the other task")
})
g.Go(func() error {
twoResult = two(ctx)
return fmt.Errorf("this will cancel the other task")
})
g.Wait()
fmt.Println(oneResult, twoResult)
}
func race2() {
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)
results := make(chan int32)
defer close(results)
g.Go(func() error {
results <- one(ctx)
return nil
})
g.Go(func() error {
results <- two(ctx)
return fmt.Errorf("this will cancel the other task")
})
var r int32
select {
case r = <-results:
cancel()
case <-ctx.Done():
panic("!") // can't happen as-is; in real code we'd return err
}
fmt.Println(r)
}
func main() {
all()
race()
race2()
}
package main
import (
"context"
"errors"
"fmt"
"golang.org/x/sync/errgroup"
//"log"
"time"
)
func fetch(ctx context.Context, n int, fail bool) (string, error) {
select {
case <-time.After(time.Duration(n) * time.Second):
if fail {
return "", errors.New("an error")
} else {
return "Hello", nil
}
case <-ctx.Done():
fmt.Println("canceled")
return "CXL", ctx.Err()
}
}
func main() {
ctx := context.Background()
g, ctx := errgroup.WithContext(ctx)
var r1, r2, r3 string
g.Go(func() error {
var err error
r1, err = fetch(ctx, 1, true)
return err
})
g.Go(func() error {
var err error
r2, err = fetch(ctx, 2, false)
return err
})
g.Go(func() error {
var err error
r3, err = fetch(ctx, 3, false)
return err
})
err := g.Wait()
fmt.Printf("err: %v, 1: %s; 2: %s; 3: %s\n", err, r1, r2, r3)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment