How to send of GO routines in a worker pool

前端 未结 1 1627
你的背包
你的背包 2021-01-27 12:03

im writing an algorithm to break down an image into segments and manipulate it, however the way im currently using Go routines isn\'t quite optimal.

I\'d like to split

相关标签:
1条回答
  • 2021-01-27 12:23

    Here you have a generic pattern for implementing concurrent image processors giving control to the caller over the image partitioning to split the work in n parts and over the concurrency level of the execution (i.e. the number of worker goroutines used for executing the (possibly different) number of processing jobs).

    See the pprocess func which implements the whole pattern taking a Partitioner and a Processor, the former being a func that takes the job of returning n image partitions to operate on, and the latter being a func which will be used for processing each partition.

    I implemented the vertical splitting you expressed in your code example in the func splitVert which returns a function which can split an image in n vertical sections.

    For doing some actual work I implemented the gray func which is a Processor that transform pixel colors to gray levels (luminance).

    Here's the working code:

    type MutableImage interface {
        image.Image
        Set(x, y int, c color.Color)
    }
    
    type Processor func(MutableImage, image.Rectangle)
    
    type Partitioner func(image.Image) []image.Rectangle
    
    func pprocess(i image.Image, concurrency int, part Partitioner, proc Processor) image.Image {
        m := image.NewRGBA(i.Bounds())
        draw.Draw(m, i.Bounds(), i, i.Bounds().Min, draw.Src)
        var wg sync.WaitGroup
        c := make(chan image.Rectangle, concurrency*2)
        for n := 0; n < concurrency; n++ {
            wg.Add(1)
            go func() {
                for r := range c {
                    proc(m, r)
                }
                wg.Done()
            }()
        }
        for _, p := range part(i) {
            c <- p
        }
        close(c)
        wg.Wait()
        return m
    }
    
    func gray(i MutableImage, r image.Rectangle) {
        for x := r.Min.X; x <= r.Max.X; x++ {
            for y := r.Min.Y; y <= r.Max.Y; y++ {
                c := i.At(x, y)
                r, g, b, _ := c.RGBA()
                l := 0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b)
                i.Set(x, y, color.Gray{uint8(l / 256)})
            }
        }
    }
    
    func splitVert(c int) Partitioner {
        return func(i image.Image) []image.Rectangle {
            b := i.Bounds()
            s := float64(b.Dy()) / float64(c)
            rs := make([]image.Rectangle, c)
            for n := 0; n < c; n++ {
                m := float64(n)
                x0 := b.Min.X
                y0 := b.Min.Y + int(0.5+m*s)
                x1 := b.Max.X
                y1 := b.Min.Y + int(0.5+(m+1)*s)
                if n < c-1 {
                    y1--
                }
                rs[n] = image.Rect(x0, y0, x1, y1)
            }
            return rs
        }
    }
    
    func main() {
        i, err := jpeg.Decode(os.Stdin)
        if err != nil {
            log.Fatalf("decoding image: %v", err)
        }
        o := pprocess(i, runtime.NumCPU(), splitVert(8), gray)
        err = jpeg.Encode(os.Stdout, o, nil)
        if err != nil {
            log.Fatalf("encoding image: %v", err)
        }
    }
    
    0 讨论(0)
提交回复
热议问题