Skip to content

Questions about code optimization #298

Closed
@shuqingzai

Description

@shuqingzai

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:

carbon/traveler.go

Lines 9 to 22 in 6fab820

func Now(timezone ...string) *Carbon {
c := NewCarbon()
if len(timezone) > 0 {
c.loc, c.Error = parseTimezone(timezone[0])
}
if c.HasError() {
return c
}
if IsTestNow() {
return frozenNow.testNow
}
c.time = time.Now().In(c.loc)
return c
}

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())
}
  1. 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
	}
}
  1. 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
  1. 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()
}
  1. 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()
	}
}
  1. 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
  1. Summary and Recommendations
  • Execution Time: The operation time for BenchmarkYesterdayV2 is approximately 47.4% of that for BenchmarkYesterday (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 than Yesterday, 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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionIndicates that an issue, pull request, or discussion needs more information

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions