-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Hi.
Studying your semaphore implementation I have written this example.
I am wondering if it is compliant with your implementation, and if yes, if it is comparable to the D.Vyukov suggested example (effective go reviews). See in the following example:
/*
Counting Semaphore.
Binary Semaphore (Edsger Dijkstra) and Counting Semaphore (Carel S. Scholten)
are 2 variants of the Semaphore scheme.
A good and short (critical) presentation here: (http://bit.ly/1OCBY9t).
The example below, is a study of the "effective go" example of a channel used as
a semaphore (see https://golang.org/doc/effective_go.html#channels):
func Serve(queue chan *Request) {
for req := range queue {
sem <- 1 // Wait for active queue to drain the buffer of chan sem.
go func(req *Request) {
process(req)
<-sem // Done; enable next request to run.
}(req)
}
}
An alternative solution, was proposed by D.Vyukov:
It initiates a fixed number of Signals (sem <- 1), that limit the number of
started goroutines by construction.
func Serve(queue chan *Request) {
sem := make(chan int, MaxOutstanding)
for i := 0; i < MaxOutstanding; i++ {
sem <- 1
}
for req := range queue {
// acquisition of the semaphore must be on a channel receive, not a send.
//
<-sem
go func() {
process(req)
sem <- 1
}
}
}
In our example, this second approach is implemented using a Counting Semaphore.
See in the code below: Acquire(n) and Release(1) n times.
To be note: we are using the robust Semaphore implementation by R.Obryk,
available here: github.com/robryk/semaphore.
*/
package main
import (
"fmt"
"github.com/semaphore"
)
var (
// max number of goroutines launched concurrently
MaxOutstanding int = 4
// a list to process
list = []int{}
)
func main() {
for i:=1; i<=10; i++ {
list = append(list, i)
}
Serve(list)
}
// Observe the difference with the 1st Effective Go example (in comment above).
// In case of overload, a 'Wait' is organized limiting the number of concurrent
// goroutines: a go throttle.
//
func Serve(queue []int) {
s := semaphore.NewSemaphore(MaxOutstanding)
msg := make(chan string)
// Wait for goroutines to drain the 'counting semaphore',
// when drained: blocks until a 'next release'!
s.Acquire(MaxOutstanding)
// start n goroutines until the s.Acquire() blocks
for i, item := range queue {
go func(i, item int) {
// any processing here
text := fmt.Sprintf("from goroutine[%d]= %d\n", i, item)
msg <- text
// Done; enable next task to run (drain the counting semaphore of 1).
s.Release(1)
}(i, item)
}
for x:=0; x < len(list); x++ {
fmt.Printf(<-msg)
}
}
Thanks in advance for your feed-back.