Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A question more than an issue, is my example correct? #1

Open
patrickToca opened this issue Oct 20, 2015 · 0 comments
Open

A question more than an issue, is my example correct? #1

patrickToca opened this issue Oct 20, 2015 · 0 comments

Comments

@patrickToca
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant