【问题标题】:Is Haskell appropriate for long-running applications?Haskell 是否适合长时间运行的应用程序?
【发布时间】:2015-08-08 19:17:54
【问题描述】:

我认为 Haskell 是一门漂亮的语言,从基准测试来看,它的实现可以生成快速代码。

但是,我想知道它是否适用于长期运行的应用程序,或者是否会追逐所有潜在的惰性引起的泄漏,人们可能会在短期应用程序中忽略这些泄漏,证明令人沮丧?

This Reddit comment 回应了我的担忧:

只要你有多个函数递归调用自身, 堆配置文件不再为您提供任何帮助来确定 正在发生泄漏。

(整个讨论似乎富有洞察力和坦率)

我个人对高性能计算很感兴趣,但我猜服务器和 HPC 有这个共同点。

如果 Haskell 适用于此类应用程序,是否有任何示例可以证明这一点,即应用程序

  1. 需要运行数天或数周,因此需要消除所有相关泄漏(程序花费在睡眠或等待某些底层 C 库返回的时间显然不算在内)
  2. 很重要(如果应用程序很简单,开发人员可以猜测泄漏源并尝试各种修复。但是,我不相信这种方法可以很好地扩展。堆配置文件在识别根据上面的 Reddit 讨论,具有多个 [相互] 递归函数的泄漏源似乎特别值得关注)

如果 Haskell 不适合此类应用程序,那为什么?

更新: Haskell 的 Yesod Web 服务器框架,作为示例提出,may have issues with memory。我想知道是否有人在连续几天服务请求后测试了它的内存使用情况。

【问题讨论】:

  • 看起来有点像带有垃圾收集器的系统是否合适:因为gc 人们通常不会销毁不再需要的对象:他们认为 gc 会找到他们最终。但这可能会导致大量堆对象仅处于活动状态,因为引用未设置为null,从而使所有这些对象成为垃圾。
  • 懒惰并不意味着空间泄漏,正如严格不意味着。管理这两种内存模型有不同的技术。您编写应用程序的方式决定了您的应用程序是否能够长时间运行。我知道Facebook is using Haskell 是多个数据存储和它们的一些前端服务之间的中间层,但我不知道这些是否是短暂的过程。我的猜测是它们需要长时间运行,所以如果是这种情况,你就会有一个非常可靠的例子。
  • @bheklilr:我不认为 MaxB 指的是空间泄漏:Haskell 正确管理内存(或者应该从理论上的 pov),但回收死对象可能需要很长时间。
  • @MaxB,你不能在 gc 语言中真正“删除所有垃圾”。我们正在谈论忘记设置对null 的某些引用,这与因为它们所引用的内容而不评估某些表达式非常相似。然而,与命令式程序相比,在 Haskell 程序中推理内存确实非常困难。你可以设计你的持久性数据结构,以保证它们没有未评估的 thunk——如果我正在编写一个大型系统,我可能会这样做。它确实限制了你的表达能力,但也为内存使用提供了一个检查点。
  • 阅读:engineering.imvu.com/2014/03/24/what-its-like-to-use-haskell。似乎 Haskell 在长时间运行的服务中运行良好,但空间泄漏可能更难找到(尽管工具正在改进,所以我不知道现在有多难)。

标签: performance haskell memory-leaks functional-programming scientific-computing


【解决方案1】:

warp Web 服务器证明 Haskell 适合长时间运行的应用程序。

当 Haskell 应用程序出现空间泄漏时,可能很难找到原因,但一旦知道原因,解决起来通常很简单(我曾经使用过的最困难的修复方法是将 zip [1..] 应用于列出并从最后一个元素获取长度,而不是使用length 函数)。但是空间泄漏实际上在 Haskell 程序中非常罕见。故意造成空间泄漏通常比修复意外泄漏更难。

【讨论】:

  • The warp web server proves... 有没有繁忙的网站在使用它?
  • github.com/yesodweb/yesod/wiki/Powered-by-Yesod 有一个不完整的使用 Yesod 框架的网站列表(这很难与其他 Web 服务器一起使用)。似乎没有人那么忙,但有时很难说。另一方面:在基准测试中,除了单核服务器外,warp 每秒处理的请求比 nginx 多。在 10 个核心服务器上:warp 比 nginx 快 5 倍。
【解决方案2】:

大多数长时间运行的应用都是请求驱动的。例如,HTTP 服务器将所有瞬态数据与 HTTP 请求相关联。请求结束后,数据被丢弃。所以至少对于那些长时间运行的应用程序,任何语言都不会出现空间泄漏。在单个请求的上下文中泄漏您想要的所有内容。只要您不创建对每个请求数据的全局引用,您就不会泄漏。

如果你改变全局状态,所有的赌注都会被取消。出于多种原因,这是要避免的,并且在此类应用中并不常见。

【讨论】:

  • 不是网络程序员,但我认为大多数 HTTP 服务器在服务请求后需要保留一些信息:日志记录、新内容(如本网站上的内容)、库存物品等。
  • @Carsten,所以也许我们正在实现一个数据库或类似的东西。
  • @luqui ???好吧,看来我是那种你不想在这里玩的奇怪孩子——好吧,我已经闭嘴了
  • 我想你听到了我为自我满足而定义问题的挫败感,这似乎发生在人们用我们喜欢的语言提出问题时......
【解决方案3】:

我有一个用 haskell 编写的服务,可以运行几个月,没有任何特定于 haskell 的问题。有一段时间它工作了 6 个月而没有任何注意,但后来我重新启动它以应用更新。它包含一个无状态的 HTTP API,但它也有有状态的 websockets 接口,所以它保持长期的生活状态。它的来源是封闭的,所以我无法提供链接,但我的经验是,haskell 可以很好地用于长时间运行的应用程序。

懒惰对我来说不是问题,但那是因为我知道如何处理它。这并不难,但需要一些经验。

此外,关于 hackage 的库具有不同的质量,控制依赖关系是很重要的。除非真的有必要,否则我会尽量避免依赖关系,并且我会检查他们的大部分代码(除了一些广泛使用的包之外,它们中的大多数要么是核心库,要么是 Haskell 平台的一部分,尽管我也检查了他们的代码——只是为了学习新事物。)

尽管存在 GHC(最广泛使用的实现)不能很好地工作的极端情况。当应用程序在内存中维护一个巨大的(主要是只读的)状态时,我遇到了 GC 时间问题(有一个ticket。)还有很多稳定的指针可能是有问题的(ticket,尽管我自己从未经历过。 ) 大多数时候,通过精心设计,可以轻松避免这种极端情况。

实际上,应用程序设计对于长时间运行的应用程序来说是最重要的事情。实现语言的作用不那么重要。可能这是我过去几年学到的最大的教训——软件设计非常重要,而且语言之间并没有太大的不同。

【讨论】:

    【解决方案4】:

    “空间泄漏”在语义上与任何语言中的任何其他类型的资源使用问题相同。在严格的语言中,GC 倾向于分配和保留过多的数据(因为结构是严格的)。

    无论是哪种语言,您都应该做一些“刻录”来随着时间的推移寻找资源使用情况,Haskell 也不例外。

    参见例如xmonad,一次运行数月或数年。这是一个 Haskell 应用程序,堆使用量很小,我通过运行数周或数月来测试它,并进行分析以分析堆模式。这让我相信资源使用是稳定的。

    最终,懒惰在这里是一条红鲱鱼。使用资源监控工具和测试来衡量和验证您的资源预期。

    【讨论】:

    • xmonad 的复杂度非常低(xmonad 不是在 99.9% 的时间里都在睡觉吗? (你的top 说什么?)xmonad 真的是在此类应用程序中使用 Haskell 的最佳示例吗?
    • xmonad的核心是
    • 我只是在问题中澄清了要求。
    【解决方案5】:

    是的。有两种可能的空间泄漏:

    堆上的数据。这里的情况与其他使用 GC 的语言没有什么不同。 (对于那些不这样做的情况通常更糟 - 如果出现错误,而不是增加内存使用量,进程可能会触及释放的内存,反之亦然,并且会严重崩溃。)

    未经评估的重击。诚然,一个人可以在脚上开枪, 当然,必须避免产生像foldl (+) 0 这样的大量重击的众所周知的情况。但是要防止这种情况并不难,对于其他泄漏,我会说它实际上比其他语言更容易,当你习惯它时。

    您要么有一个长时间运行的繁重计算,要么有一个响应请求的服务。如果您有一个长时间运行的计算,您通常需要在计算结果时立即获得结果,这会强制对其进行评估。

    如果您有一个服务,它的状态通常是包含良好的,因此很容易确保它总是在请求结束时被评估。事实上,与其他语言相比,Haskell 使这更容易:在 Haskell 中,您不能让程序的组件保持自己的内部状态。应用程序的全局状态或者在某种主循环中作为参数线程化,或者使用IO 存储。并且由于 Haskell 应用程序的良好设计尽可能地限制和本地化 IO,它再次使状态易于控制。


    作为另一个示例,Ganeti 项目(我是该项目的开发人员)使用了多个 Haskell 长时间运行的守护进程。

    根据我们的经验,内存泄漏非常罕见,如果我们遇到问题,通常是与其他资源(如文件描述符)有关。我记得的唯一最近的案例是监控守护程序在收集数据但没有人查看它们的罕见情况下泄漏内存作为 thunk (这将迫使他们进行评估)。 fix was rather simple

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-08
      • 2013-12-15
      • 2020-07-20
      • 1970-01-01
      • 2018-02-24
      • 2016-04-30
      • 2018-11-29
      • 2017-02-26
      相关资源
      最近更新 更多