DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Rust’s Ownership and Borrowing Enforce Memory Safety
  • Secrets in Code: Understanding Secret Detection and Its Blind Spots
  • Exploring Exciting New Features in Java 17 With Examples
  • Sliding Window

Trending

  • LLM-Powered Deep Parsing for Industrial Inventory Search
  • OpenAPI From Code With Spring and Java: A Recipe for Your CI
  • How SaaS Architectures Break at Scale — and the Engineering Decisions That Prevent It
  • When Snowflake Lies to You: Understanding False Failures in dbt Pipelines
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. Make Your Go Code Work 1.5x Faster or Even More

Make Your Go Code Work 1.5x Faster or Even More

This article will explain how to make your GO code run faster. Performance is key in everything; we want to save time.

By 
Michael Ushakov user avatar
Michael Ushakov
·
Updated Nov. 24, 22 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
6.7K Views

Join the DZone community and get the full member experience.

Join For Free

Performance is a key thing in everything; we (humans) don't like to wait and waste our time. Therefore, sometimes quick solutions, as most of the managers suppose, are better than slow ones but with good engineering and design. But today, we are not speaking about management but about code performance. We have a small text formatting library that allows us to format text using a template in a convenient on our view way. These not only formatting functions do what fmt.Sprintf does this in a more convenient way but also provides additional features. Previous versions of our module were loose in performance to fmt.Sprintf, but since 1.0.1, we are better. And today, we are going to tell you how to make any golang code work faster.

Parameters and Return Values

There are two options to pass either argument and/or get function result - by pointer and by value; consider the following example:

 
func getItemAsStr(item *interface{}) string   // 1st variant
func getItemAsStr(item interface{})  string   // 2nd variant
func getItemAsStr(item *interface{}) *string  // 3rd variant
func getItemAsStr(item interface{})  *string  // 4th variant


According to our performance tests, we could conclude the following:

  1. We've got a small performance rise when we pass arguments by pointer because we've got rid of arguments copying.
  2. We've got a performance decrease when we return a pointer to the function local variable.

Therefore, the most optimal variant is the first variant.

Strings

Strings are immutable like in many other programming languages; therefore, string concatenation using the + operator is a bad idea, i.e. code like this is very slow:

 
var result string = ""
for _, arg := range args {    result += getItemAsStr(&arg)
}


Every "+" creates a new string object; as a result, memory usage rise, and performance significantly decreases due to spending sufficient time on allocations to new variables.

There is a better solution for string Concat —  use strings.Builder, but for better performance, you should initially enlarge the buffer (using Grow function) to prevent it from some / all re-allocs, but if the buffer size will be very large, there will be a penalty to performance due to initial memory allocation will be slow; therefore you should choose initial buffer size wisely, i.e.:

 
var formattedStr = &strings.Builder{}
formattedStr.Grow(templateLen + 22*len(args))


Cycles

There are two ways to iterate over the collection:

  • Using range expression:
 
  for _, arg := range args {      // do some staff here  }


  • Using traditional for with three expressions:
 
  for i := start; i < templateLen; i++ {      // do some staff here  }


The second variant is better in performance. But there are additional advantages of usage for three expressions:

  • Reduce the number of iterations; more iteration code is slower; therefore, if you could affect your loop value, do it. This can't be achieved with range;
  • Set the initial value for iteration much higher if it is possible, i.e. in our case:
 
  start := strings.Index(template, "{")  if start < 0 {     return template  }
  formattedStr.WriteString(template[:start])  for i := start; i < templateLen; i++ {      // iterate over i  }


Conclusion

Using such simple techniques, we made our code run 1.5 times faster than it was, and now it works faster even than fmt.Sprintf, see our performance measurements:

performance measurements

GitHub Golang Library Requirements engineering Buffer (application) Memory (storage engine) Pass (software) Pointer (computer programming) Strings Template

Published at DZone with permission of Michael Ushakov. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Rust’s Ownership and Borrowing Enforce Memory Safety
  • Secrets in Code: Understanding Secret Detection and Its Blind Spots
  • Exploring Exciting New Features in Java 17 With Examples
  • Sliding Window

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook