Skip to content

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

@patrickToca

Description

@patrickToca

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions