迭代过程的流与尾递归
这是我之前的问题的后续问题。
我知道我们可以使用streams
来生成“pi”(和其他数字)、n-th fibonacci等的近似值。但是我怀疑streams是否可以
是执行此操作的正确方法。
主要缺点(据我所知)是内存消耗:例如 stream
将保留 i stream
的所有斐波那契数。 n 而我只需要斐波那契第 n 次。当然,我可以使用 drop
但它使解决方案变得更加复杂。尾递归看起来是更适合此类任务的方法。
你怎么认为?
This is a follow-up to my previous question.
I understand that we can use streams
to generate an approximation of 'pi' (and other numbers), n-th fibonacci, etc. However I doubt if streams
is the right approach to do that.
The main drawback (as I see it) is memory consumption: e.g. stream
will retains all fibonacci numbers for i < n while I need only fibonacci n-th. Of course, I can use drop
but it makes the solution a bit more complicated. The tail recursion
looks like a more suitable approach to the tasks like that.
What do you think?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果需要快速行驶,请轻装上阵。这意味着;避免分配任何不必要的内存。如果您需要内存,请使用可用的快速集合。如果您知道需要多少内存;预分配。对于计算而言,分配绝对是性能杀手。你的代码可能看起来不再好看,但它会运行得很快。
但是,如果您正在使用 IO(磁盘、网络)或任何用户交互,那么分配就显得苍白无力了。那么最好将优先级从代码性能转移到可维护性。
If need to go fast, travel light. That means; avoid allocation of any unneccessary memory. If you need memory, use the fastast collections available. If you know how much memory you need; preallocate. Allocation is the absolute performance killer... for calculation. Your code may not look nice anymore, but it will go fast.
However, if you're working with IO (disk, network) or any user interaction then allocation pales. It's then better to shift priority from code performance to maintainability.
使用迭代器。它不保留中间值。
Use Iterator. It does not retain intermediate values.
如果您想要第 n 个斐波那契数并使用流作为临时数据结构(如果您不保存对先前计算的流元素的引用),那么您的算法将在恒定空间中运行。
以前计算的 Stream 元素(不再使用)将被垃圾收集。由于它们是在最年轻的一代中分配并立即收集的,因此几乎所有分配都可能在缓存中。
更新:
看来 Stream 的当前实现并不像它可能的那样节省空间,主要是因为它继承了 LinearSeqOptimized 特征的
apply
方法的实现,它定义为Reference to a head of a stream is hold here by
this
and prevents the stream from being gc'ed. So combination ofdrop
andhead
methods (as inf.drop(100).head
) may be better for situations where dropping intermediate results is feasible. (thanks to Sebastien Bocq for explaining this stuff on scala-user).If you want n-th fibonacci number and use a stream just as a temporary data structure (if you do not hold references to previously computed elements of stream) then your algorithm would run in constant space.
Previously computed elements of a Stream (which are not used anymore) are going to be garbage collected. And as they were allocated in the youngest generation and immediately collected, allmost all allocations might be in cache.
Update:
It seems that the current implementation of Stream is not as space-efficient as it may be, mainly because it inherits an implementation of
apply
method from LinearSeqOptimized trait, where it is defined asReference to a head of a stream is hold here by
this
and prevents the stream from being gc'ed. So combination ofdrop
andhead
methods (as inf.drop(100).head
) may be better for situations where dropping intermediate results is feasible. (thanks to Sebastien Bocq for explaining this stuff on scala-user).