Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 1 | # Bounding resource use |
| 2 | |
nathany | ad56cb2 | 2014-12-10 09:37:30 -0800 | [diff] [blame] | 3 | To bound a program's use of a limited resource - like memory - have goroutines synchronize their use of that resource using a buffered channel (i.e., use the channel as a semaphore): |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 4 | |
nathany | ad56cb2 | 2014-12-10 09:37:30 -0800 | [diff] [blame] | 5 | ```go |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 6 | const ( |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 7 | AvailableMemory = 10 << 20 // 10 MB |
| 8 | AverageMemoryPerRequest = 10 << 10 // 10 KB |
| 9 | MaxOutstanding = AvailableMemory / AverageMemoryPerRequest |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 10 | ) |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 11 | |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 12 | var sem = make(chan int, MaxOutstanding) |
| 13 | |
| 14 | func Serve(queue chan *Request) { |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 15 | for { |
| 16 | sem <- 1 // Block until there's capacity to process a request. |
| 17 | req := <-queue |
| 18 | go handle(req) // Don't wait for handle to finish. |
| 19 | } |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 20 | } |
| 21 | |
| 22 | func handle(r *Request) { |
Dave Day | 0d6986a | 2014-12-10 15:02:18 +1100 | [diff] [blame] | 23 | process(r) // May take a long time & use a lot of memory or CPU |
| 24 | <-sem // Done; enable next request to run. |
Andrew Gerrand | 5bc444d | 2014-12-10 11:35:11 +1100 | [diff] [blame] | 25 | } |
| 26 | ``` |
| 27 | |
| 28 | ## References |
| 29 | |
| 30 | Effective Go's discussion of channels: http://golang.org/doc/effective_go.html#channels |