github.com/anishathalye/periscope@v0.3.5/internal/par/map.go (about) 1 package par 2 3 import ( 4 "reflect" 5 "runtime" 6 "sync" 7 ) 8 9 var defaultWorkers = runtime.NumCPU() 10 11 type MapFunc = func(key, value interface{}, emit func(x interface{})) 12 13 func Map(v interface{}, mapper MapFunc) <-chan interface{} { 14 return MapN(v, defaultWorkers, mapper) 15 } 16 17 func MapN(v interface{}, workers int, mapper MapFunc) <-chan interface{} { 18 type task struct { 19 key interface{} 20 value interface{} 21 } 22 r := reflect.ValueOf(v) 23 kind := r.Kind() 24 if !(kind == reflect.Map || kind == reflect.Slice || kind == reflect.Array || kind == reflect.Chan) { 25 panic("not a map, slice, array, or channel") 26 } 27 tasks := make(chan task) 28 results := make(chan interface{}) 29 emit := func(x interface{}) { 30 results <- x 31 } 32 var wg sync.WaitGroup 33 // spawn workers 34 for i := 0; i < workers; i++ { 35 wg.Add(1) 36 go func() { 37 defer wg.Done() 38 for t := range tasks { 39 mapper(t.key, t.value, emit) 40 } 41 }() 42 } 43 // feed workers 44 go func() { 45 switch kind { 46 case reflect.Map: 47 iter := r.MapRange() 48 for iter.Next() { 49 k := iter.Key() 50 v := iter.Value() 51 tasks <- task{k.Interface(), v.Interface()} 52 } 53 case reflect.Slice, reflect.Array: 54 for i := 0; i < r.Len(); i++ { 55 tasks <- task{i, r.Index(i).Interface()} 56 } 57 case reflect.Chan: 58 for i := 0; ; i++ { 59 x, ok := r.Recv() 60 if !ok { 61 break 62 } 63 tasks <- task{i, x.Interface()} 64 } 65 } 66 close(tasks) 67 // wait for workers, close results when done 68 wg.Wait() 69 close(results) 70 }() 71 return results 72 }