如何高效地构建一个 Golang 程序以实现最佳垃圾回收运行?

huangapple go评论82阅读模式
英文:

How do I efficiently structure a golang program for optimum garbage collector runs?

问题

最近,随着Go语言强化的时间优化GC运行,优化代码以获得更好的结果似乎变得更加重要。最近有人告诉我,一次运行中它所完成的工作"取决于你对堆内存使用的模式",但从程序员的角度来看,我不太确定这究竟意味着什么。或者这不是一个容易控制的事情吗?

我已经阅读了Brian W. Kernighan的最新著作《Go程序设计语言》,但其中没有提到这个主题。而且互联网上关于这个主题的所有信息都是几年前的,所以并不适用。

我目前做的一些事情包括:

  • 确保指针/对象只在需要的地方存储/记忆
  • 分配具有预期容量或合理容量的对象
  • 不重复数据
  • 在可以的情况下,通过函数流式传输数据,而不是一次性将所有数据放入大堆中。

我还对字符串和字节数组在彼此转换时总是重新创建的事实感到有些恼火(因为字符串是不可变的)。所以当我从一个类型转换到另一个类型时,如果是安全操作,我只需使用unsafe将它们的指针重新转换为另一种类型。

所有这些做法是否值得帮助GC更快地运行和清理更多的内存?还有其他我可以做的事情吗?

英文:

Optimizing code for better results in the golang GC seems to be more of a rather important thing recently with the strongly time-optimized GC runs. I was recently told how much it accomplishes in a run "depends on your pattern of heap memory usage.", but I'm not really sure exactly what that means/entails from the perspective of a programmer in the language. Or is that not something that can easily be controlled?

I have read through the recent book "The Go Programming Language" by Brian W. Kernighan, but there is nothing about this topic in it. And all information on this topic on the internet are from years ago, so don't really apply.

Some things I currently do include:

  • Making sure pointers/objects are only ever stored/remembered where they need to be
  • Allocating objects with capacities of what are expected or are sane
  • Not duplicating data
  • When able, using streaming data through functions instead of putting all data into a big heap up front.

I am also a bit annoyed by the fact that strings and byte arrays are always recreated when converting between one or the other (due to strings being immutable). So when I am going from one to the other, and its a safe operation, I just recast their pointers to the other type using unsafe.

Are all of these practices worth it to help the GC run faster and clear more? Is there anything else I could do?

答案1

得分: 6

如果只是简单地列出一些要做和不要做的事项,我们可以编写一个程序来优化内存使用。

第一步是编写正确、设计良好、易于维护和易于阅读的代码。

接下来,使用Go的测试包来对关键函数进行基准测试。例如,一个真实的案例,

BenchmarkOriginal  	   30000     44349 ns/op	   52792 B/op	   569 allocs/op

使用Go的性能分析工具。阅读源代码和可执行代码,了解正在发生的情况。

实施策略,例如使用单个底层数组和完整的切片表达式,以减少GC内存分配和CPU时间。运行最终的基准测试。

BenchmarkOptimized 	  100000     13198 ns/op	   32992 B/op	     3 allocs/op

在这种情况下,将一个三角数组的569个元素的分配减少到3个,分配减少了99%,相应的CPU时间减少了70%。垃圾收集器(GC)的工作也减少了很多。

当然,这使得代码更难阅读(更复杂和更晦涩),因此也更难维护。

不要过度优化。你真的没有更好的事情要做吗?最好的优化通常是购买一台更大的计算机。

英文:

If it were a simple matter of a list of do's and don'ts we could simply write a program to optimize memory usage.

The first step is to write correct, well-designed, maintainable, and easy-to-read code.

Next, using Go's testing package, benchmark critical functions. For example. a real case,

BenchmarkOriginal  	   30000     44349 ns/op	   52792 B/op	   569 allocs/op

Use Go's profile tool. Read the source and executable code to see what is going on.

Implement strategies, such a single underlying array and full slice expressions, to reduce GC memory allocations and CPU time. Run a final benchmark.

BenchmarkOptimized 	  100000     13198 ns/op	   32992 B/op	     3 allocs/op

In this case, 569 allocations of the elements of a triangular array were reduced to 3 allocations, a 99% reduction in allocations with a corresponding 70% reduction in CPU time. There's a lot less for the garbage collector (GC) to do too.

Of course, this made the code harder to read (more complex and more obscure) and thus harder to maintain.

Don't over optimize. Do you really have nothing better to do? The best optimization is often buying a bigger computer.

huangapple
  • 本文由 发表于 2016年2月8日 08:01:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/35260745.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定