Is image/draw thread safe?

// CompositeImage numSizeRatio is num + '#' size_ratio
func CompositeImage(numSizeRatio string, imageUrls []string) ([]byte, error) {
	compositeImageParameter := CompositeImageParameterMap[numSizeRatio]
	basemap := image.NewRGBA(image.Rect(0, 0, compositeImageParameter.BaseImageWidth, compositeImageParameter.BaseImageHeight))
	var wg sync.WaitGroup
	for i := 0; i < len(imageUrls); i++ {
		wg.Add(1)
		go func(i int) {
			defer func() {
				if err := recover(); err != nil {
					log.Errorf("panic stack: %s", string(debug.Stack()))
					log.Error("CompositeImage panic:", err)
				}
				wg.Done()
			}()
			imageBytes, err := util.GetRaw(imageUrls[i])
			if err != nil {
				log.Errorf("GetRaw image %d error: %v", i, err)
				return
			}

			buffer := bytes.NewBuffer(imageBytes)
			imageDecode, err := webp.Decode(buffer)
			if err != nil {
				imageDecode, _, err = image.Decode(bytes.NewBuffer(imageBytes))
				if err != nil {
					log.Errorf("Decode image %d error: %v", i, err)
					return
				}
			}
			draw.Draw(basemap, image.Rect(compositeImageParameter.Offset[i][0], compositeImageParameter.Offset[i][1], compositeImageParameter.Offset[i][2], compositeImageParameter.Offset[i][3]),
				imageDecode, imageDecode.Bounds().Min, draw.Over)
		}(i)
	}
	wg.Wait()

	outputImageBytes := bytes.NewBuffer([]byte{})
	if err := png.Encode(outputImageBytes, basemap); err != nil {
		return nil, errors.Wrap(err, "png Encode error")
	}

	return outputImageBytes.Bytes(), nil
}

I use go test -race. It doesn’t have errors.

I wouldn’t assume that it is safe unless the documentation indicates that it is or you’ve examined the source code to check that it has appropriate synchronization.

The race detector only finds races that happen at runtime

You have a lot of other time consuming operations in your goroutine, so you are are probably lucky that Draw isn’t called simultaneously. Considering that you have I/O and allocation operations, you aren’t going to get much parallelism anyway. Your multiple goroutines mainly help with asynchronous I/O. So be safe and put your Draw in another separate goroutine and send the data to it through a chan (the first 3 proverbs https://go-proverbs.github.io/ are relevant here) or protect it with a mutex.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.