Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(733)

Delta Between Two Patch Sets: doc/effective_go.html

Issue 75130045: code review 75130045: doc: allow buffered channel as semaphore without initia... (Closed)
Left Patch Set: Created 11 years ago
Right Patch Set: diff -r e2fb4c83d69d https://code.google.com/p/go/ Created 11 years ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | doc/go_mem.html » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 <!--{ 1 <!--{
2 "Title": "Effective Go", 2 "Title": "Effective Go",
3 "Template": true 3 "Template": true
4 }--> 4 }-->
5 5
6 <h2 id="introduction">Introduction</h2> 6 <h2 id="introduction">Introduction</h2>
7 7
8 <p> 8 <p>
9 Go is a new language. Although it borrows ideas from 9 Go is a new language. Although it borrows ideas from
10 existing languages, 10 existing languages,
(...skipping 2924 matching lines...) Expand 10 before | Expand all | Expand 10 after
2935 Receivers always block until there is data to receive. 2935 Receivers always block until there is data to receive.
2936 If the channel is unbuffered, the sender blocks until the receiver has 2936 If the channel is unbuffered, the sender blocks until the receiver has
2937 received the value. 2937 received the value.
2938 If the channel has a buffer, the sender blocks only until the 2938 If the channel has a buffer, the sender blocks only until the
2939 value has been copied to the buffer; if the buffer is full, this 2939 value has been copied to the buffer; if the buffer is full, this
2940 means waiting until some receiver has retrieved a value. 2940 means waiting until some receiver has retrieved a value.
2941 </p> 2941 </p>
2942 <p> 2942 <p>
2943 A buffered channel can be used like a semaphore, for instance to 2943 A buffered channel can be used like a semaphore, for instance to
2944 limit throughput. In this example, incoming requests are passed 2944 limit throughput. In this example, incoming requests are passed
2945 to <code>handle</code>, which receives a value from the channel, processes 2945 to <code>handle</code>, which sends a value into the channel, processes
2946 the request, and then sends a value back to the channel 2946 the request, and then receives a value from the channel
2947 to ready the "semaphore" for the next consumer. 2947 to ready the &ldquo;semaphore&rdquo; for the next consumer.
2948 The capacity of the channel buffer limits the number of 2948 The capacity of the channel buffer limits the number of
2949 simultaneous calls to <code>process</code>, 2949 simultaneous calls to <code>process</code>.
2950 so during initialization we prime the channel by filling it to capacity.
2951 </p> 2950 </p>
2952 <pre> 2951 <pre>
2953 var sem = make(chan int, MaxOutstanding) 2952 var sem = make(chan int, MaxOutstanding)
2954 2953
2955 func handle(r *Request) { 2954 func handle(r *Request) {
2956 &lt;-sem // Wait for active queue to drain. 2955 sem &lt;- 1 // Wait for active queue to drain.
2957 process(r) // May take a long time. 2956 process(r) // May take a long time.
2958 sem &lt;- 1 // Done; enable next request to run. 2957 &lt;-sem // Done; enable next request to run.
2959 }
2960
2961 func init() {
2962 for i := 0; i &lt; MaxOutstanding; i++ {
2963 sem &lt;- 1
2964 }
2965 } 2958 }
2966 2959
2967 func Serve(queue chan *Request) { 2960 func Serve(queue chan *Request) {
2968 for { 2961 for {
2969 req := &lt;-queue 2962 req := &lt;-queue
2970 go handle(req) // Don't wait for handle to finish. 2963 go handle(req) // Don't wait for handle to finish.
2971 } 2964 }
2972 } 2965 }
2973 </pre> 2966 </pre>
2974 2967
2975 <p> 2968 <p>
2976 Because data synchronization occurs on a receive from a channel 2969 Once <code>MaxOutstanding</code> handlers are executing <code>process</code>,
2977 (that is, the send "happens before" the receive; see 2970 any more will block trying to send into the filled channel buffer,
2978 <a href="/ref/mem">The Go Memory Model</a>), 2971 until one of the existing handlers finishes and receives from the buffer.
2979 acquisition of the semaphore must be on a channel receive, not a send.
2980 </p> 2972 </p>
2981 2973
2982 <p> 2974 <p>
2983 This design has a problem, though: <code>Serve</code> 2975 This design has a problem, though: <code>Serve</code>
2984 creates a new goroutine for 2976 creates a new goroutine for
2985 every incoming request, even though only <code>MaxOutstanding</code> 2977 every incoming request, even though only <code>MaxOutstanding</code>
2986 of them can run at any moment. 2978 of them can run at any moment.
2987 As a result, the program can consume unlimited resources if the requests come in too fast. 2979 As a result, the program can consume unlimited resources if the requests come in too fast.
2988 We can address that deficiency by changing <code>Serve</code> to 2980 We can address that deficiency by changing <code>Serve</code> to
2989 gate the creation of the goroutines. 2981 gate the creation of the goroutines.
2990 Here's an obvious solution, but beware it has a bug we'll fix subsequently: 2982 Here's an obvious solution, but beware it has a bug we'll fix subsequently:
2991 </p> 2983 </p>
2992 2984
2993 <pre> 2985 <pre>
2994 func Serve(queue chan *Request) { 2986 func Serve(queue chan *Request) {
2995 for req := range queue { 2987 for req := range queue {
2996 &lt;-sem 2988 sem &lt;- 1
2997 go func() { 2989 go func() {
2998 process(req) // Buggy; see explanation below. 2990 process(req) // Buggy; see explanation below.
2999 sem &lt;- 1 2991 &lt;-sem
3000 }() 2992 }()
3001 } 2993 }
3002 }</pre> 2994 }</pre>
3003 2995
3004 <p> 2996 <p>
3005 The bug is that in a Go <code>for</code> loop, the loop variable 2997 The bug is that in a Go <code>for</code> loop, the loop variable
3006 is reused for each iteration, so the <code>req</code> 2998 is reused for each iteration, so the <code>req</code>
3007 variable is shared across all goroutines. 2999 variable is shared across all goroutines.
3008 That's not what we want. 3000 That's not what we want.
3009 We need to make sure that <code>req</code> is unique for each goroutine. 3001 We need to make sure that <code>req</code> is unique for each goroutine.
3010 Here's one way to do that, passing the value of <code>req</code> as an argument 3002 Here's one way to do that, passing the value of <code>req</code> as an argument
3011 to the closure in the goroutine: 3003 to the closure in the goroutine:
3012 </p> 3004 </p>
3013 3005
3014 <pre> 3006 <pre>
3015 func Serve(queue chan *Request) { 3007 func Serve(queue chan *Request) {
3016 for req := range queue { 3008 for req := range queue {
3017 &lt;-sem 3009 sem &lt;- 1
3018 go func(req *Request) { 3010 go func(req *Request) {
3019 process(req) 3011 process(req)
3020 sem &lt;- 1 3012 &lt;-sem
3021 }(req) 3013 }(req)
3022 } 3014 }
3023 }</pre> 3015 }</pre>
3024 3016
3025 <p> 3017 <p>
3026 Compare this version with the previous to see the difference in how 3018 Compare this version with the previous to see the difference in how
3027 the closure is declared and run. 3019 the closure is declared and run.
3028 Another solution is just to create a new variable with the same 3020 Another solution is just to create a new variable with the same
3029 name, as in this example: 3021 name, as in this example:
3030 </p> 3022 </p>
3031 3023
3032 <pre> 3024 <pre>
3033 func Serve(queue chan *Request) { 3025 func Serve(queue chan *Request) {
3034 for req := range queue { 3026 for req := range queue {
3035 &lt;-sem
3036 req := req // Create new instance of req for the goroutine. 3027 req := req // Create new instance of req for the goroutine.
3028 sem &lt;- 1
3037 go func() { 3029 go func() {
3038 process(req) 3030 process(req)
3039 sem &lt;- 1 3031 &lt;-sem
3040 }() 3032 }()
3041 } 3033 }
3042 }</pre> 3034 }</pre>
3043 3035
3044 <p> 3036 <p>
3045 It may seem odd to write 3037 It may seem odd to write
3046 </p> 3038 </p>
3047 3039
3048 <pre> 3040 <pre>
3049 req := req 3041 req := req
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after
3637 <pre> 3629 <pre>
3638 verifying implementation 3630 verifying implementation
3639 type Color uint32 3631 type Color uint32
3640 3632
3641 // Check that Color implements image.Color and image.Image 3633 // Check that Color implements image.Color and image.Image
3642 var _ image.Color = Black 3634 var _ image.Color = Black
3643 var _ image.Image = Black 3635 var _ image.Image = Black
3644 </pre> 3636 </pre>
3645 --> 3637 -->
3646 3638
LEFTRIGHT
« no previous file | doc/go_mem.html » ('j') | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b