-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
regexp: regexp causes lock contention #24411
Comments
Does copying the regexes across multiple goroutines help ? https://golang.org/pkg/regexp/#Regexp.Copy
|
Copying works in that the contention goes away, but adds pressure to the GC and increases memory usage. The code would have to be radically changed to support regexp copies per-goroutine, and Go maintainers have pushed back on cpu-local variables (which would fit the need ideally). Note that this issue is about improving the performance of the internal Regexp machine cache, not about adding any new features or capabilities. |
That's #18802, and it's under active investigation. But a CPU-local variable wouldn't necessarily work here: if the input is large (or the regexp is very complex), it's entirely possible that the goroutine will be descheduled (and rescheduled on a different CPU/thread) midway through the call.
|
Change https://golang.org/cl/101715 mentions this issue: |
@rsc has CLs for this for Go 1.12: https://go-review.googlesource.com/c/go/+/122476 |
@rsc - Just wanted to check up on this. I believe your regexp related CLs for 1.12 takes care of this ? Or is there still something to be done on this ? |
Marking fixed from: https://golang.org/cl/139779 That final commit adds the "Deprecated" text: // Copy returns a new Regexp object copied from re.
// Calling Longest on one copy does not affect another.
//
// Deprecated: In earlier releases, when using a Regexp in multiple goroutines,
// giving each goroutine its own copy helped to avoid lock contention.
// As of Go 1.12, using Copy is no longer necessary to avoid lock contention.
// Copy may still be appropriate if the reason for its use is to make
// two copies with different Longest settings.
func (re *Regexp) Copy() *Regexp {
re2 := *re
return &re2
} |
Please answer these questions before submitting your issue. Thanks!
What version of Go are you using (
go version
)?go1.10
Does this issue reproduce with the latest release?
I'm using the latest release.
What operating system and processor architecture are you using (
go env
)?linux/amd64
What did you do?
I'm testing the Prometheus server 2.1 (prometheus.io) under high load (>300k samples/s), and I'm seeing contention within Regexp that prevents scaling further (see goroutines profile below). My investigation shows that this is caused by the lock around the machine objects.
I wrapped the Regexp objects in the Prometheus code with a sync.Pool, and the lock contention went away, allowing me to scale up to 500k samples/s and beyond (I'm in the process of load testing and I haven't found the new ceiling at the time of this post).
I would like to propose changing the Regexp implementation to use sync.Pool instead of a slice and a mutex. This is a very simple change limited to the Regexp.get and Regexp.put methods in https://golang.org/src/regexp/regexp.go. I'm happy to send in the change if this proposal gets accepted.
Redacted goroutine profile:
The text was updated successfully, but these errors were encountered: