You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+38-16
Original file line number
Diff line number
Diff line change
@@ -113,22 +113,44 @@ deadline for the match. The performance impact is as follows.
113
113
is reached. E.g., if you set a timeout of one minute the load will persist
114
114
for approximately a minute even if the match finishes quickly.
115
115
116
-
Some alternative implementations were considered and ruled out.
117
-
118
-
1.**time.Now()** - This was the initial timeout implementation. It called `time.Now()`
119
-
and compared the result to the deadline approximately once every 1000 matching steps.
120
-
Adding a timeout to a simple match increased the cost from ~45ns to ~3000ns).
121
-
2.**time.AfterFunc** - This approach entails using `time.AfterFunc` to set an `expired`
122
-
atomic boolean value. However it increases the cost of handling a simple match
123
-
with a timeout from ~45ns to ~360ns and was therefore ruled out.
124
-
3.**counter** - In this approach an atomic variable tracks the number of live matches
125
-
with timeouts. The background clock stops when the counter hits zero. The benefit
126
-
of this approach is that the background load will stop more quickly (after the
127
-
last match has finished as opposed to waiting until the deadline for the last
128
-
match). However this approach requires more atomic variable updates and has poorer
129
-
performance when multiple matches are executed concurrently. (The cost of a
130
-
single match jumps from ~45ns to ~65ns, and the cost of running matches on
131
-
all 12 available CPUs jumps from ~400ns to ~730ns).
116
+
See [PR #58](https://github.com/dlclark/regexp2/pull/58) for more details and
117
+
alternatives considered.
118
+
119
+
## Goroutine leak error
120
+
If you're using a library during unit tests (e.g. https://github.com/uber-go/goleak) that validates all goroutines are exited then you'll likely get an error if you or any of your dependencies use regex's with a MatchTimeout.
121
+
To remedy the problem you'll need to tell the unit test to wait until the backgroup timeout goroutine is exited.
122
+
123
+
```go
124
+
funcTestSomething(t *testing.T) {
125
+
defer goleak.VerifyNone(t)
126
+
defer regexp2.StopTimeoutClock()
127
+
128
+
// ... test
129
+
}
130
+
131
+
//or
132
+
133
+
funcTestMain(m *testing.M) {
134
+
// setup
135
+
// ...
136
+
137
+
// run
138
+
m.Run()
139
+
140
+
//tear down
141
+
regexp2.StopTimeoutClock()
142
+
goleak.VerifyNone(t)
143
+
}
144
+
```
145
+
146
+
This will add ~100ms runtime to each test (or TestMain). If that's too much time you can set the clock cycle rate of the timeout goroutine in an init function in a test file. `regexp2.SetTimeoutCheckPeriod` isn't threadsafe so it must be setup before starting any regex's with Timeouts.
147
+
148
+
```go
149
+
funcinit() {
150
+
//speed up testing by making the timeout clock 1ms
151
+
regexp2.SetTimeoutCheckPeriod(time.Millisecond)
152
+
}
153
+
```
132
154
133
155
## ECMAScript compatibility mode
134
156
In this mode the engine provides compatibility with the [regex engine](https://tc39.es/ecma262/multipage/text-processing.html#sec-regexp-regular-expression-objects) described in the ECMAScript specification.
0 commit comments