I have written a linux service in Go that processes a large number of image files, converting them from TIFF to JPEG and adding a text overlay on top. I'm using the Go package gographics/imagick/v3 based in CGO to do this. The machine I run this on has 64 logical cores, 96GB of RAM and I run Rocky Linux 9.5 with REMI's ImageMagick7 packages installed.
In my code I launch a worker pool of 50 goroutines, each running the func I use to convert the images. I initialize imagick globally at the top of the main func with a deferred imagick.Terminate(). In the image convert func I establish a new magickwand, drawingwand and pixelwand. If at any point there is an issue with an image, the wands are cleared and the goroutine loops back to check the channel for another job. After all images are completed, the goroutine exits and all the wands are destroyed.
Since this is a service, it never exits, but after it completes a processing job, I see in htop that there are 70-80 threads in an idle state owned by the service PID. If I process multiple jobs, that number of idle threads never gets any larger, but it never goes away either. I'm assuming these are helper threads established by the ImageMagick Wand library? If I stop the service, the threads are released and when I start my service there are only 6 threads until something is processed.
I have disabled any OpenMP, MKL, OpenBlas settings I can find via environment variables and setting whatever resource limits in the imagick library I can. I have each goroutine use runtime.LockOSThread to set affinity of the imagick function in each goroutine, but nothing changes. The leftover threads remain.
If I look at the threads in gdb or by cat-ing the status in /proc/PID/task/TID/status I'm shown they are in futex and nothing more than that. The threads aren't taking up any CPU resources and other than whatever RAM a native thread consumes, they're not using that up much either.
Has anyone else ever had experience with Go and Imagick and seen something like this? Have I stumbled on a bug or is this just normal for Go an Imagick when performing the kind of processing I'm doing in a long running app like a service?
Thanks