Last active
October 9, 2020 22:14
-
-
Save besser/986a3e13759082e5620d1863b4b40480 to your computer and use it in GitHub Desktop.
Semaphore pattern example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"fmt" | |
"log" | |
"time" | |
"golang.org/x/sync/semaphore" | |
) | |
func main() { | |
ctx := context.TODO() | |
var ( | |
maxWorkers = 1000 | |
routines = 1000000 | |
sem = semaphore.NewWeighted(int64(maxWorkers)) | |
) | |
fmt.Println("Starting...") | |
for i := 0; i < routines; i++ { | |
if err := sem.Acquire(ctx, 1); err != nil { | |
log.Printf("Failed to acquire semaphore: %v", err) | |
break | |
} | |
go func(n int) { | |
defer sem.Release(1) | |
routine(n) | |
}(i) | |
} | |
if err := sem.Acquire(ctx, int64(maxWorkers)); err != nil { | |
log.Printf("Failed to acquire semaphore: %v", err) | |
} | |
fmt.Println("Done!") | |
} | |
func routine(n int) { | |
fmt.Printf("go routine %d\n", n) | |
// take a time | |
time.Sleep(100 * time.Millisecond) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"errors" | |
"fmt" | |
"log" | |
"math/rand" | |
"time" | |
"golang.org/x/sync/semaphore" | |
) | |
func main() { | |
ctx, cancel := context.WithCancel(context.Background()) | |
defer cancel() // Make sure it's called to release resources even if no errors | |
var ( | |
maxWorkers = 1000 | |
routines = 1000000 | |
sem = semaphore.NewWeighted(int64(maxWorkers)) | |
) | |
errs := make(chan error, 2) // Buffer for 2 errors | |
fmt.Println("Starting...") | |
for i := 0; i < routines; i++ { | |
if err := sem.Acquire(ctx, 1); err != nil { | |
log.Printf("Failed to acquire semaphore: %v", err) | |
break | |
} | |
go func(n int) { | |
defer sem.Release(1) | |
// Check if any error occurred in any other gorouties: | |
select { | |
case <-ctx.Done(): | |
return // Error somewhere, terminate | |
default: // Default is must to avoid blocking | |
} | |
err := routine(n) | |
if err != nil { | |
errs <- fmt.Errorf("Worker #%d, error: %v\n", i, err) | |
cancel() | |
return | |
} | |
}(i) | |
} | |
if err := sem.Acquire(ctx, int64(maxWorkers)); err != nil { | |
log.Printf("Failed to acquire semaphore: %v", err) | |
} | |
// Return error, if any: | |
if ctx.Err() != nil { | |
fmt.Printf("Finished with error: %v", <-errs) | |
} else { | |
fmt.Println("Finished ok!") | |
} | |
fmt.Println("Done!") | |
} | |
func routine(n int) error { | |
fmt.Printf("go routine %d\n", n) | |
if rand.Intn(100) < 10 { // 10% of failure | |
return errors.New("random error") | |
} | |
// take a time | |
time.Sleep(100 * time.Millisecond) | |
return nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"time" | |
) | |
type empty struct{} | |
type semaphore chan empty | |
func main() { | |
maxWorkers := 1000 | |
routines := 1000000 | |
sem := make(semaphore, maxWorkers) | |
e := empty{} | |
fmt.Println("Starting...") | |
for i := 0; i < routines; i++ { | |
sem <- e | |
go func(n int) { | |
defer func() { | |
<-sem | |
}() | |
routine(n) | |
}(i) | |
} | |
sem.P() | |
fmt.Println("Done!") | |
} | |
func routine(n int) { | |
fmt.Printf("go routine %d\n", n) | |
// take a time | |
time.Sleep(100 * time.Millisecond) | |
} | |
// fill resources | |
func (s semaphore) P() { | |
e := empty{} | |
for i := 0; i < cap(s); i++ { | |
s <- e | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment