【问题标题】:Are Iteratees safe for managing resources?Iteratees 管理资源是否安全?
【发布时间】:2014-09-18 12:19:07
【问题描述】:

假设我正在阅读InputStream

我通常会怎么做:

val inputStream = ...
try {
    doStuff(inputStream)
} finally {
    inputStream.close()
}

无论doStuff是否抛出异常,我们都会关闭InputStream


我将如何使用迭代器:

val inputStream ...
Enumerator.fromStream(inputStream)(Iteratee.foreach(doStuff))

InputStream 是否会被关闭(即使doStuff 抛出异常)?

一个小测试:

val inputStream = new InputStream() { // returns 10, 9, ... 0, -1
    private var i = 10
    def read() = {
       i = math.max(0, i) - 1
       i
    }
    override def close() = println("closed") // looking for this
}
Enumerator.fromStream(inputStream)(Iteratee.foreach(a => 1 / 0)).onComplete(println)

我们只看到:

Failure(java.lang.ArithmeticException: / by zero)

流从未关闭。将1 / 0 替换为1 / 1,您会看到流关闭了。

当然,我可以保持对原始流的引用并在失败时关闭它,但 AFAIK 使用 iteratees 的想法是创建可组合的迭代而不必这样做。


  1. 这是预期的行为吗?

  2. 有没有办法使用迭代器以便始终正确处理资源?

【问题讨论】:

  • 请注意,这种行为在 2.2 中发生了变化(尽管它仍然有点奇怪)。我从来没有真正认为 Play 的迭代实现有一个非常好的资源管理故事。

标签: scala playframework-2.1 iterate resource-management


【解决方案1】:

迭代器专为安全资源管理而设计。见第一句Iteratee IO: safe, practical, declarative input processing

Iteratee IO 是一种具有精确资源控制的增量输入处理方式。

这个想法是,当您的资源仅通过迭代器访问时,拥有资源的代码可以准确地判断迭代器何时完成资源并立即关闭它。另一方面,当手动管理迭代时(如传统的InputStream),资源的用户负责关闭它。这可能会导致泄漏。

也就是说,Play 2.1 中存在一个错误,其中fromStream 没有管理其底层InputStream 的关闭!此错误已在 Play 2.2 中修复。

您可以查看fromStream code,了解如何通过使用onDoneEnumerating 在迭代完成时关闭资源来修复Enumerator

【讨论】:

  • 哦,很好,我很高兴这是一个错误,而不是有意或根本的限制:)
猜你喜欢
  • 2014-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-19
  • 1970-01-01
  • 2020-08-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多