我最初在 Java 中采用了非常实用的方法,即每次都在运行中派生所有内容,最大限度地减少属性和计算方法的使用。但是对于较大的数据集,我开始遇到性能问题,并且多次调用相同的方法来只计算相同的结果似乎是多余的,有时还会对性能造成指数拖累。
我终于开始采用数据密集型操作的方法,将我的方法设置为仅在第一次调用时计算并保存结果以备将来返回。
这是不好的做法吗?
计算一次方法并保存结果是不好的做法吗?
这个1没有正确的一般答案。这取决于具体情况。
习惯性地到处这样做是不好的做法(IMO)。JIT 编译器能够进行各种自动优化,使这种手动优化毫无意义……甚至有害。(一般来说,手动优化是不值得的,除非您使用真实的输入数据分析了整个应用程序,并且分析告诉您在代码中的特定点有一个性能热点。)
如果您这样做是出于习惯(即不假思索),您可能会降低代码的可读性,并且可能会使其变慢而不是变快。如果您每次编写方法调用时都在考虑它,那将影响您的工作效率。
当您有充分的理由相信方法调用可能很昂贵时,这样做并不是一个坏习惯。但是,请考虑您的直觉可能是错误的,最好依靠分析来告诉您在哪里花费精力。(见上文关于生产力的注释。)
如果您根据应用程序级别的基准测试确定性能是一个真正的问题,并且您通过分析确定这些调用的手动优化是有必要的,那么这样做是一种很好的做法。
如果该方法有副作用并且您不希望副作用发生两次,则这是必要的。
如果该方法有副作用并且您需要每次都发生副作用,这是不正确的。
另一件要考虑的事情是这是否有助于或阻碍可读性......以及可维护性对您的项目而言是否比性能更重要。
1 ...以及声称存在的答案过于概括和/或过于教条。说真的,伙计们,事情没那么简单。
不,还不错。这实际上是一个很好的做法。
首先,如果您正在计算数据并再次执行此操作,那么您确实在 Java 中犯下了巨大的罪行。正如您所说,我们必须尽量减少内存的使用,并且计算会占用大量内存。
其次,第一次计算运算并将其保存在变量中是最佳实践之一。下次您再次需要该值时,只需调用该变量即可。
不,不是,如果您遇到性能问题,这是一个很好的做法。但是,如果您不这样做,则可能会被视为过早优化。这种优化技术称为记忆化。
一般的答案是函数是否正在做一些事情,阻止编译器确定它总是返回相同的结果。例如,如果函数正在读取外部数据,例如从磁盘或网络中读取。
如果编译器无法从根本上确定这种“不可变”行为,那么您应该存储并重用任何此类调用的结果。
如果编译器确实可以确定,至少在原则上,结果将是相同的——例如,计算第 n 个斐波那契数的函数——那么这取决于编译器的复杂程度。函数式编程语言,尤其是。Haskell 是专门设计的,除了少数例外,所有函数都保证为相同的参数返回相同的值,因此所有实现都会自动进行此类缓存。
但是,对于不是以这种方式设计的语言(Java 就是其中之一),编译器极不可能确定您的斐波那契代码可以说是“不可变的”。因此,您应该自己存储和重用该值。
最后需要注意的是,对于诸如计算百分比的函数之类的近乎微不足道的操作,这样做不值得额外的复杂性。
更新:您的问题似乎不是是否存储和重用函数返回的值,而是函数本身保持内部缓存。除了从不同代码区域调用的已识别热点并且这些代码区域之间没有简单的方法相互协调之外,我建议不要这样做。那是因为缓存这些值有一些缺点——你可能会浪费一些内存来缓存实际上可能不再需要的值;更糟糕的是,这些值可能会驱逐最终再次被需要的值;第三,有额外的指令和内存访问来检查一个值是否在缓存中。
存储和重用的逻辑最好保留在函数之外,以便它可以比缓存进行更精确的存储和重用。