mirror of
https://github.com/restic/restic.git
synced 2024-09-14 06:59:41 +02:00
85 lines
2.0 KiB
Go
85 lines
2.0 KiB
Go
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style
|
||
|
// license that can be found in the LICENSE file.
|
||
|
|
||
|
package semaphore_test
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"runtime"
|
||
|
|
||
|
"golang.org/x/sync/semaphore"
|
||
|
)
|
||
|
|
||
|
// Example_workerPool demonstrates how to use a semaphore to limit the number of
|
||
|
// goroutines working on parallel tasks.
|
||
|
//
|
||
|
// This use of a semaphore mimics a typical “worker pool” pattern, but without
|
||
|
// the need to explicitly shut down idle workers when the work is done.
|
||
|
func Example_workerPool() {
|
||
|
ctx := context.TODO()
|
||
|
|
||
|
var (
|
||
|
maxWorkers = runtime.GOMAXPROCS(0)
|
||
|
sem = semaphore.NewWeighted(int64(maxWorkers))
|
||
|
out = make([]int, 32)
|
||
|
)
|
||
|
|
||
|
// Compute the output using up to maxWorkers goroutines at a time.
|
||
|
for i := range out {
|
||
|
// When maxWorkers goroutines are in flight, Acquire blocks until one of the
|
||
|
// workers finishes.
|
||
|
if err := sem.Acquire(ctx, 1); err != nil {
|
||
|
log.Printf("Failed to acquire semaphore: %v", err)
|
||
|
break
|
||
|
}
|
||
|
|
||
|
go func(i int) {
|
||
|
defer sem.Release(1)
|
||
|
out[i] = collatzSteps(i + 1)
|
||
|
}(i)
|
||
|
}
|
||
|
|
||
|
// Acquire all of the tokens to wait for any remaining workers to finish.
|
||
|
//
|
||
|
// If you are already waiting for the workers by some other means (such as an
|
||
|
// errgroup.Group), you can omit this final Acquire call.
|
||
|
if err := sem.Acquire(ctx, int64(maxWorkers)); err != nil {
|
||
|
log.Printf("Failed to acquire semaphore: %v", err)
|
||
|
}
|
||
|
|
||
|
fmt.Println(out)
|
||
|
|
||
|
// Output:
|
||
|
// [0 1 7 2 5 8 16 3 19 6 14 9 9 17 17 4 12 20 20 7 7 15 15 10 23 10 111 18 18 18 106 5]
|
||
|
}
|
||
|
|
||
|
// collatzSteps computes the number of steps to reach 1 under the Collatz
|
||
|
// conjecture. (See https://en.wikipedia.org/wiki/Collatz_conjecture.)
|
||
|
func collatzSteps(n int) (steps int) {
|
||
|
if n <= 0 {
|
||
|
panic("nonpositive input")
|
||
|
}
|
||
|
|
||
|
for ; n > 1; steps++ {
|
||
|
if steps < 0 {
|
||
|
panic("too many steps")
|
||
|
}
|
||
|
|
||
|
if n%2 == 0 {
|
||
|
n /= 2
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
const maxInt = int(^uint(0) >> 1)
|
||
|
if n > (maxInt-1)/3 {
|
||
|
panic("overflow")
|
||
|
}
|
||
|
n = 3*n + 1
|
||
|
}
|
||
|
|
||
|
return steps
|
||
|
}
|