From what you have already shown, using strconv.Atoi
directly improved your performance. You can push it further and flip your own atoi
for your specific use case.
You expect each element to be a positive base number of 10. You also know that it cannot overflow, since the maximum length of the transmitted string representation is 4. The only possible error is an asymmetric character in the string. Knowing this, we can simply do the following:
var atoiError = errors.New("invalid number") func atoi(s string) (x int, err error) { i := 0 for ; i < len(s); i++ { c := s[i] if c < '0' || c > '9' { err = atoiError return } x = x*10 + int(c) - '0' } return }
Wrapping this in ParseDate3
, I get the following result:
BenchmarkParseDate1 5000000 355 ns/op BenchmarkParseDate2 10000000 278 ns/op BenchmarkParseDate3 20000000 88 ns/op
You can do it faster without returning an error in atoi
, but I urge you to test the input anyway (unless it is verified somewhere else in your code).
Alternative atoi approach after viewing the inline solution:
By clicking this even further, you can take advantage of the fact that all but one of the transmitted lines are 2 digits in length (a 4-digit year, but it is multiplied by two). Creating atoi using a 2-digit string will eliminate the for
loop. Example:
// Converts string of 2 characters into a positive integer, returns -1 on error func atoi2(s string) int { x := uint(s[0]) - uint('0') y := uint(s[1]) - uint('0') if x > 9 || y > 9 { return -1 // error } return int(x*10 + y) }
Converting a year into a number will require a two-step approach:
year := atoi2(strdate[0:2])*100 + atoi2(strdate[2:4])
This gives an additional improvement:
BenchmarkParseDate4 50000000 61 ns/op
Please note that the embedded version suggested by @peterSO is only slightly faster (54 ns / op in my case), but the solution above gives you the ability to check for errors, while the embedded version blindly accepts all characters, converting them to dates.