Closed
Description
Post-initialization Carbon
I see that many methods of converting Carbon initialize in the first line, even though errors may occur. Can we avoid a large number of initializations when encountering errors?
See:
Lines 9 to 22 in 6fab820
Maybe:
func NowV2(timezone ...string) *Carbon {
if IsTestNow() {
return frozenNow.testNow
}
if len(timezone) > 0 {
loc, err := parseTimezone(timezone[0])
if err != nil {
return &Carbon{Error: err} // when timezone is invalid, return error
}
return CreateFromStdTime(time.Now().In(loc))
}
return CreateFromStdTime(time.Now())
}
- Benchmark
func BenchmarkNow(b *testing.B) {
for n := 0; n < b.N; n++ {
// Now()
Now("ERROR") // error
}
}
func BenchmarkNowV2(b *testing.B) {
for n := 0; n < b.N; n++ {
// NowV2()
NowV2("ERROR") // error
}
}
- Testing
# only Now()
#╰─⠠⠵ go test -bench="BenchmarkNow*" -benchmem
lang en
goos: darwin
goarch: amd64
pkg: github.com/dromara/carbon/v2
cpu: Intel(R) Core(TM) i5-8500B CPU @ 3.00GHz
BenchmarkNow-6 98043 12169 ns/op 4488 B/op 76 allocs/op
BenchmarkNowV2-6 98161 13254 ns/op 4488 B/op 76 allocs/op
PASS
ok github.com/dromara/carbon/v2 3.218s
# when error
#╰─⠠⠵ go test -bench="BenchmarkNow*" -benchmem
lang en
goos: darwin
goarch: amd64
pkg: github.com/dromara/carbon/v2
cpu: Intel(R) Core(TM) i5-8500B CPU @ 3.00GHz
BenchmarkNow-6 19142 62904 ns/op 46231 B/op 97 allocs/op
BenchmarkNowV2-6 25220 46978 ns/op 41855 B/op 22 allocs/op
PASS
ok github.com/dromara/carbon/v2 3.985s
- Summary and Recommendations
- In the no-error scenario, the performance of BenchmarkNow and BenchmarkNowV2 is similar.
- In the error scenario, BenchmarkNowV2 significantly outperforms BenchmarkNow, with lower average execution time, less memory allocation, and fewer allocation counts.
Copy Used
In some auxiliary methods, why do we need to perform Copy based on Now? Wouldn't it be better to return the newly created instance directly?
See:
Maybe:
// YesterdayV2 returns a Carbon instance for yesterday.
// 昨天
func YesterdayV2(timezone ...string) *Carbon {
now := NowV2(timezone...) // used V2
if now.IsInvalid() {
return now
}
// No Copy is needed, because now is a newly created structure and there is no reference relationship?
return now.SubDay()
}
- Benchmark
func BenchmarkYesterday(b *testing.B) {
for n := 0; n < b.N; n++ {
Yesterday()
}
}
func BenchmarkYesterdayV2(b *testing.B) {
for n := 0; n < b.N; n++ {
YesterdayV2()
}
}
- Testing
#╰─⠠⠵ go test -bench="BenchmarkYesterday*" -benchmem
lang en
goos: darwin
goarch: amd64
pkg: github.com/dromara/carbon/v2
cpu: Intel(R) Core(TM) i5-8500B CPU @ 3.00GHz
BenchmarkYesterday-6 41296 26878 ns/op 11312 B/op 162 allocs/op
BenchmarkYesterdayV2-6 95168 12740 ns/op 4488 B/op 76 allocs/op
PASS
ok github.com/dromara/carbon/v2 4.264s
- Summary and Recommendations
- Execution Time: The operation time for
BenchmarkYesterdayV2
is approximately 47.4% of that forBenchmarkYesterday
(12,740 / 26,878 ≈ 0.474). - Memory Allocation: The memory allocation for
BenchmarkYesterdayV2
has been reduced by about 60.4% (4,488 / 11,312 ≈ 0.397). - Object Allocation: The object allocation for
BenchmarkYesterdayV2
has been reduced by about 53.1% (76 / 162 ≈ 0.47). - From the test report, it is evident that the performance of
YesterdayV2
is significantly better thanYesterday
, primarily due to lower execution time, reduced memory allocation, and fewer object allocations.
Other Ideas
Perhaps we should revisit the Carbon codebase and optimize its performance?