【问题标题】:How to safely use reply and !? on a Scala Actor如何安全地使用回复和!?在 Scala 演员上
【发布时间】:2013-01-03 19:58:48
【问题描述】:

依赖于来自 Scala Actor 的 reply 对我来说似乎非常容易出错。这真的是在演员之间进行对话的惯用 Scala 方式吗?有没有我想念的reply 的替代方法或更安全的用法?

(关于我:我熟悉 Java 中的同步,但我之前从未设计过基于 Actor 的系统,也没有完全理解范式。)

错误示例

为了一个简单的演示,让我们看看这个愚蠢的整数解析 Actor:

import actors._, Actor._

val a = actor {
  loop {
    react {
      case s: String => reply(s.toInt)
    }
  }
}

我们可以打算将其用作

scala> a !? "42"
res0: Any = 42

但如果演员没有回复(在这种情况下,因为粗心的程序员没有想到在演员中捕捉NumberFormatException),我们将永远等待:

scala> a !? "f"

我们在呼叫现场也犯了一个错误。下一个示例也无限期阻塞,因为参与者不回复Int 消息:

scala> a !? 42

超时

如果预期回复有一些已知的合理时间限制,您可以使用!? (msec: Long, msg: Any),但在我能想到的大多数情况下并非如此。

保证回复

一种想法是设计该actor,使其必须回复每条消息:

import actors._, Actor._

val a = actor {
  loop {
    react {
      case m => reply { 
        try {
          m match {
            case s: String => reply(s.toInt)
            case _ => None
          }
        } catch {
          case e => e
        }
      }
    }
  }
}

这感觉好多了,虽然还是有点担心不小心调用!? 对不再演戏的演员。

【问题讨论】:

    标签: scala actor


    【解决方案1】:

    我可以理解您的担忧,但我实际上认为这并不比您习惯的同步更糟糕。谁保证锁会再次被释放?

    使用!? 需要您自担风险,因此我知道没有“更安全”的用法。线程可以阻塞或死亡,我们绝对无能为力。除了提供可以减轻打击的安全阀。

    基于事件的行为实际上为您提供了同步接收回复的替代方案。超时是其中之一,但另一件事是通过!! 方法实现的Futures。它们旨在处理诸如此类的死锁。该方法立即返回可以稍后处理的未来。

    有关灵感和更深入的设计决策,请参阅:

    演员: http://docs.scala-lang.org/overviews/core/actors.html

    期货(在 Scala 2.10 中): http://docs.scala-lang.org/sips/pending/futures-promises.html

    【讨论】:

      【解决方案2】:

      不要打扰老当地演员 - 学习Akka。你知道synchronized 也很好,但就我个人而言——几乎从不使用这样的词,即使在Java 代码中也是如此。想象一下synchronized 已被弃用,学习Java 内存模型,学习CAS

      【讨论】:

      • 使用“同步”而不使用其他原语,很可能会意外编写死锁的程序。因为 javadoc 不显示何时使用“同步”,所以它存在原则上难以缓解的耦合风险,例如调用闭源 API。所以谨慎对待它是明智的。
      【解决方案3】:

      我本人并不熟悉 Scala 标准库中的 Actor 系统,但我强烈建议您查看 Akka 工具包 (http://akka.io/),它已“替换”了 Scala Actors,并从 Scala 2.10 开始随 Scala 发行版一起提供.

      总体而言,在 Actor 系统设计方面,一些关键思想是异步(非阻塞)、隔离可变性和通过消息传递进行通信。每个 Actor 都封装了自己的状态,不允许其他任何人触摸它。您可以向 Actor 发送一条可能“要求”它更改状态的消息,但 Actor 实现可以随意忽略它。消息是异步发送的(你可以让它阻塞,不推荐)。如果您想要某种“响应”(以便您可以将消息与之前发送的消息关联),Scala 2.10 中的 Future API 和 Akka 的 ask 可以提供帮助。

      关于您的错误格式异常和一般问题,请考虑查看 Scala 2.10 和 Akka 2.1 中的 askFuture API。它将处理异常并且是非阻塞的。

      Scala 2.10 还有一个新的Try,旨在替代老式的try-catch 子句。 Try 有一个apply 方法,您可以像使用任何try 一样使用它(减去catchfinally)。 Try 有两个子类 SuccessFailureTry[T] 的实例将具有子类 Success[T]Failure[Throwable]。通过例子更容易解释:

      >>> val x: Try[Int] = Try { "5".toInt } // Success[Int] with encapsulated value 5
      >>> val y: Try[Int] = Try { "foo".toInt } // Failure(java.lang.NumberFormatException: For input string: "foo")
      

      由于Try 不会抛出实际异常,并且子类是方便的案例类,因此您可以轻松地将结果用作给 Actor 的消息。

      【讨论】:

        猜你喜欢
        • 2011-08-14
        • 1970-01-01
        • 1970-01-01
        • 2013-06-16
        • 2023-03-30
        • 1970-01-01
        • 2018-05-23
        • 2011-01-20
        • 2011-01-30
        相关资源
        最近更新 更多