Metered concurrency: Difference between revisions
Content added Content deleted
(→Go, Buffered channel: small improvement to code, more explanation.) |
|||
Line 606: | Line 606: | ||
=={{header|Go}}== |
=={{header|Go}}== |
||
===Buffered channel=== |
===Buffered channel=== |
||
Recommended solution for simplicity. Acquire operation is channel send, release is channel receive, and count is provided with len(channel) |
Recommended solution for simplicity. Acquire operation is channel send, release is channel receive, and count is provided with len(channel). |
||
To demonstrate, this example implements the [https://en.wikipedia.org/wiki/Semaphore_(programming)#Library_analogy Library analogy] from Wikipedia with 10 study rooms and 20 students. |
|||
The channel type shown here is <code>struct{}</code>. <code>struct{}</code> is nice because it has zero size and zero content, although the syntax is slightly akward. Other popular choices for no-content tokens are ints and bools. They read a little nicer but waste a few bytes and could potentially mislead someone to think the values had some meaning. |
|||
A couple of other concurrency related details used in the example are the log package for serializing output and sync.WaitGroup used as a completion checkpoint. Functions of the fmt package are not synchronized and can produce interleaved output with concurrent writers. The log package does nice synchronization to avoid this. |
|||
<lang go>package main |
<lang go>package main |
||
import ( |
import ( |
||
"log" |
"log" |
||
Line 615: | Line 621: | ||
"time" |
"time" |
||
) |
) |
||
// log package serializes output |
// log package serializes output |
||
var fmt = log.New(os.Stdout, "", 0) |
var fmt = log.New(os.Stdout, "", 0) |
||
// library analogy per WP article |
// library analogy per WP article |
||
const nRooms = 10 |
const nRooms = 10 |
||
const nStudents = 20 |
const nStudents = 20 |
||
func main() { |
func main() { |
||
// buffered channel used as a counting semaphore |
// buffered channel used as a counting semaphore |
||
rooms := make(chan |
rooms := make(chan struct{}, nRooms) |
||
for i := 0; i < nRooms; i++ { |
for i := 0; i < nRooms; i++ { |
||
rooms <- |
rooms <- struct{}{} |
||
} |
} |
||
// WaitGroup used to wait for all students to have studied |
// WaitGroup used to wait for all students to have studied |
||
Line 639: | Line 645: | ||
studied.Wait() |
studied.Wait() |
||
} |
} |
||
func student(rooms chan |
func student(rooms chan struct{}, studied *sync.WaitGroup) { |
||
<-rooms |
<-rooms // acquire operation |
||
// report per task descrption. also exercise count operation |
// report per task descrption. also exercise count operation |
||
fmt.Printf("Room entered. Count is %d. Studying...\n", |
fmt.Printf("Room entered. Count is %d. Studying...\n", |
||
len(rooms)) // len function provides count operation |
len(rooms)) // len function provides count operation |
||
time.Sleep(2 * time.Second) // sleep per task description |
time.Sleep(2 * time.Second) // sleep per task description |
||
rooms <- |
rooms <- struct{}{} // release operation |
||
studied.Done() // signal that student is done |
studied.Done() // signal that student is done |
||
}</lang> |
}</lang> |
||
Output for this and the other Go programs here shows 10 students studying immediately, about a 2 second pause, 10 more students studying, then another pause of about 2 seconds before returning to the command prompt. |
Output for this and the other Go programs here shows 10 students studying immediately, about a 2 second pause, 10 more students studying, then another pause of about 2 seconds before returning to the command prompt. In this example the count values may look jumbled. This is a result of the student goroutines running concurrently. |
||
===Sync.Cond=== |
===Sync.Cond=== |