github.com/biogo/biogo@v1.0.4/concurrent/processor.go (about) 1 // Copyright ©2011-2012 The bíogo Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package concurrent 6 7 import ( 8 "fmt" 9 "runtime" 10 "sync" 11 ) 12 13 // Interface is a type that performs an operation on itself, returning any error. 14 type Operator interface { 15 Operation() (interface{}, error) 16 } 17 18 // The Processor type manages a number of concurrent Processes. 19 type Processor struct { 20 in chan Operator 21 out chan Result 22 stop chan struct{} 23 work chan struct{} 24 threads int 25 wg *sync.WaitGroup 26 } 27 28 // Return a new Processor to operate the function f over the number of threads specified taking 29 // input from queue and placing the result in buffer. Threads is limited by GOMAXPROCS, if threads is greater 30 // GOMAXPROCS or less than 1 then threads is set to GOMAXPROCS. 31 func NewProcessor(queue chan Operator, buffer int, threads int) (p *Processor) { 32 if available := runtime.GOMAXPROCS(0); threads > available || threads < 1 { 33 threads = available 34 } 35 36 p = &Processor{ 37 in: queue, 38 out: make(chan Result, buffer), 39 stop: make(chan struct{}), 40 work: make(chan struct{}, threads), 41 threads: threads, 42 wg: &sync.WaitGroup{}, 43 } 44 for i := 0; i < threads; i++ { 45 p.work <- struct{}{} 46 } 47 48 for i := 0; i < threads; i++ { 49 p.wg.Add(1) 50 go func() { 51 <-p.work 52 defer func() { 53 if err := recover(); err != nil { 54 p.out <- Result{nil, fmt.Errorf("concurrent: processor panic: %v", err)} 55 } 56 p.work <- struct{}{} 57 if len(p.work) == p.threads { 58 close(p.out) 59 } 60 p.wg.Done() 61 }() 62 63 for input := range p.in { 64 v, e := input.Operation() 65 if p.out != nil { 66 p.out <- Result{v, e} 67 } 68 select { 69 case <-p.stop: 70 return 71 default: 72 } 73 } 74 }() 75 } 76 77 return 78 } 79 80 // Submit values for processing. 81 func (p *Processor) Process(value ...Operator) { 82 for _, v := range value { 83 p.in <- v 84 } 85 } 86 87 // Get the next available result. 88 func (p *Processor) Result() (interface{}, error) { 89 r := <-p.out 90 return r.Value, r.Err 91 } 92 93 // Close the queue. 94 func (p *Processor) Close() { 95 close(p.in) 96 } 97 98 // Return the number of working goroutines. 99 func (p *Processor) Working() int { 100 return p.threads - len(p.work) 101 } 102 103 // Terminate the goroutines. 104 func (p *Processor) Stop() { 105 close(p.stop) 106 } 107 108 // Wait for all running processes to finish. 109 func (p *Processor) Wait() { 110 p.wg.Wait() 111 } 112 113 type Result struct { 114 Value interface{} 115 Err error 116 }