-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
Proposal Details
A common use of time.ParseDuration is to check whether a string is a valid time.Duration. However, when the string is not a valid duration, this function can be slow and allocate more memory:
func BenchmarkParseDurationError(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseDuration("9007199254.740993") // missing unit
}
}
/*
BenchmarkParseDurationError-10 19131199 64.33 ns/op 104 B/op 3 allocs/op
BenchmarkParseDurationError-10 18929782 63.66 ns/op 104 B/op 3 allocs/op
BenchmarkParseDurationError-10 19234929 63.45 ns/op 104 B/op 3 allocs/op
*/As a comparison, a successful parsing operation takes only 20 - 40ns and requires no memory allocation.
This function runs slowly because it extensively uses code like errors.New(“time: invalid duration ” + quote(orig)) to dynamically allocate memory along the error path. In most cases, the code only checks err != nil and does not use the information within, making these memory allocations unnecessary.
The new ParseDurationError allows the creation of error message strings to be deferred until its Error method is called, thereby reducing memory allocation and providing structured error information.
ParseDurationError could be like:
type ParseDurationError struct {
Message string
Duration string
}
// newParseDurationError creates a new ParseDurationError.
// The provided duration is cloned to avoid escaping.
func newParseDurationError(message, duration string) *ParseDurationError
func (e *ParseDurationError) Error() stringThis can make the code nearly 50% faster and use 50% less memory:
BenchmarkParseDurationError-10 40923620 28.11 ns/op 56 B/op 2 allocs/op
BenchmarkParseDurationError-10 42267286 28.22 ns/op 56 B/op 2 allocs/op
BenchmarkParseDurationError-10 42015886 28.33 ns/op 56 B/op 2 allocs/op
Compatibility:
- Error messages format won't be changed. All error messages currently follow a simple and fixed format.
- The actual type of the return value will be altered. Since
errors.Newreturns an internal type that cannot be directly used in user code, it is unlikely to break existing code.