我认为Haskell是一种优秀的语言,从基准测试来看,它的实现可以生成快速的代码。
但是,我想知道它是否适合长期运行的应用程序,或者是否会追逐所有潜在的懒惰引发的泄漏,人们可能会在短期应用程序中忽略这些泄漏,这会让人感到沮丧吗?
This Reddit comment回应我的担忧:
只要有多个函数递归调用自身, 堆配置文件不再给你任何帮助,以确定在哪里 泄漏正在发生。
(整个讨论似乎很有洞察力和坦率)
我个人对高性能计算很感兴趣,但我想服务器和HPC有这个共同的要求。
如果Haskell适用于此类应用程序,是否有任何证明这一点的示例,那就是应用程序
如果Haskell不适合此类应用程序,为什么呢?
更新:Haskell的Yesod Web服务器框架,作为示例提出,may have issues with memory。我想知道是否有人在连续几天提出请求后测试了它的内存使用情况。
答案 0 :(得分:14)
"空间泄漏"在语义上与任何语言中的任何其他类型的资源使用问题相同。在严格的语言中,GC倾向于分配和保留过多的数据(因为结构严格)。
不管你应该做什么语言"烧伤"随着时间的推移寻找资源使用,Haskell也不例外。
参见例如xmonad
,一次运行数月或数年。它是一个Haskell应用程序,有一个很小的堆使用,我通过运行数周或数月进行测试,分析堆模式。这让我相信资源使用是稳定的。
最终,懒惰在这里是一个红色的鲱鱼。使用资源监控工具和测试来衡量和验证您的资源期望。
答案 1 :(得分:8)
warp Web服务器证明Haskell适用于长期运行的应用程序。
当Haskell应用程序有空间泄漏时,可能很难找到原因,但一旦知道原因通常很容易解决(我用过的最难的解决办法就是将zip [1..]
应用于列表并从最后一个元素获取长度,而不是使用length
函数。但是在Haskell程序中,空间泄漏实际上是非常罕见的。与修复意外事故相比,故意造成空间泄漏通常更难。
答案 2 :(得分:5)
大多数长时间运行的应用都是请求驱动的。例如,HTTP服务器将所有瞬态数据与HTTP请求相关联。请求结束后,数据将被丢弃。因此,至少对于那些长期运行的应用程序,任何语言都不会有空间泄漏。在单个请求的上下文中泄露您想要的所有内容。只要您不为每个请求数据创建全局引用,就不会泄漏。
如果你改变全球状态,所有赌注都会被取消。要避免出于多种原因,这种应用程序并不常见。
答案 3 :(得分:5)
是的。有两种可能的空间泄漏:
堆上的数据。此处的情况与使用GC的其他语言没有什么不同。 (对于那些情况通常更糟的情况 - 如果出现错误,而不是增加内存使用量,该过程可能会触及释放的内存,反之亦然,只会严重崩溃。)
未经评估的thunk。不可否认,人们可以在脚下射击,
当然,必须避免产生像foldl (+) 0
这样的大型thunk的众所周知的情况。但是要防止这种情况并不困难,而且对于其他泄漏,当你习惯它时,我会说它比其他语言更容易。
要么是长时间运行,计算量大,要么是响应请求的服务。如果你有一个长时间运行的计算,你通常需要在计算时立即得到结果,这会强制进行评估。
如果你有服务,它的状态通常都很好,所以很容易确保它总是在请求结束时进行评估。实际上,与其他语言相比,Haskell使这变得更容易:在Haskell中,您不能让程序的组件保持其自己的内部状态。应用程序的全局状态在某种主循环中作为参数进行线程化,或者使用IO
进行存储。由于Haskell应用程序的良好设计限制并尽可能地IO
本地化,因此它再次使状态易于控制。
另一个例子是Ganeti项目(我是开发人员)使用了几个Haskell长期运行的守护进程。
根据我们的经验,内存泄漏非常罕见,如果我们遇到问题,通常会使用其他资源(如文件描述符)。我记得的唯一一个近期案例是监控守护程序在极少数情况下将内存泄漏为收集数据,但是没有人看过它们(这将迫使他们进行评估)。 fix was rather simple。
答案 4 :(得分:2)
我有一个用haskell编写的服务,可以工作几个月,没有任何特定于haskell的问题。有一段时间它没有任何注意工作6个月,但后来我重新启动它以应用更新。它包含无状态HTTP API,但它还具有statefull websockets接口,因此它维持长生存状态。它的来源是封闭的,所以我无法提供链接,但我的经验haskell适用于长期运行的应用程序。
懒惰不是我的问题,但那是因为我知道如何处理它。这并不难,但需要一些经验。
hackage上的库也有不同的质量,控制依赖是一件很重要的事情。我试图避免依赖,除非它们确实是必要的,我检查他们的大部分代码(除了一些广泛使用的包,大多数是核心库或Haskell平台的一部分,虽然我也检查他们的代码 - 只是为了学习新事物。)
虽然GHC(使用最广泛的实施方案)不能很好地运作,但是存在极端情况。当应用程序在内存中维护一个巨大的(主要是只读状态)时,我遇到了GC时间问题(有ticket。)此外,许多稳定指针可能会出现问题(ticket,尽管我从来没有我自己经历过这种情况。)大多数时候,通过精心设计很容易避免这种角落的情况。
实际上,应用程序设计对于长时间运行的应用程序来说是最重要的。实施语言起着不太重要的作用。可能这是我过去几年学到的最重要的一课 - 软件设计非常重要,而且语言之间也没有太大差别。