【问题标题】:understanding threadedness of actors in scala理解scala中actor的线程
【发布时间】:2012-09-06 03:16:59
【问题描述】:

有人告诉我,(Scala)Actor 实际上从不同时执行两个操作,这表明 act(或 react?或 receive?)方法本质上是同步的。我知道 act 方法中的长时间操作会导致阻塞问题,并且我假设必须以某种方式同步对消息队列的访问......但是......

建议的是,接收到告诉它递增内部计数器的消息的参与者将以线程安全的方式递增计数器。不会同时处理两条更新消息,因此没有两条消息可以尝试同时更新计数器。

actor 中的计数器属性听起来像“共享状态”。

这样的操作真的是完全线程安全的吗?如果是这样,演员如何以某种有效的方式利用多个核心机器?演员怎么是多线程的?

如果不是,那么以线程安全的方式对消息进行计数而不需要一些同步/易失变量的适当惯用方法是什么?

【问题讨论】:

    标签: multithreading scala functional-programming actor


    【解决方案1】:

    Actor 模型可用于将可变状态与外界隔离。当您有一个可变状态(例如,分配给多个并发进程的全局 ID 注册表)时,您可以将该可变状态包装在一个 Actor 中,并让客户端通过消息传递与 Actor 通信。这样,只有参与者直接访问可变状态,正如您所说,客户端消息排队等待读取和处理。消息不可变很重要。

    为避免队列变满,消息处理(reactreceive 等)尽可能短很重要。长时间运行的任务应该交给其他参与者:

    1.  Actor A receives a message M from sender S
    2.  A spawns a new actor C
    3.  A sends (S, f(M)) to C
    4.  In parallel:
    4a. A starts processing the next message.
    4b. C does the long-running or dangerous (IO) task,
        When finished, sends the result to S,
        and C terminates.
    

    过程中的一些替代方案:

    • C 将(S, result) 发回给 A,A 转发给 S
    • A 保持一个映射ActorRef C => (Sender S, Message M)so in case it sees C fail,它可以用新的Actor重试处理M。

    总而言之,Actor 是多线程的,以至于多个客户端可以从不同的线程向它发送多条消息,并且保证 Actor 将串行处理所有这些消息(尽管排序可能受到各种非过于严格的约束)。

    请注意,虽然 Actor 的 react 代码 may be executed on various threads 在单个给定时间点上仅在单个给定线程上执行(您可以想象,Actor 在调度程序认为合适的情况下从一个线程跳到另一个线程,但这是一个技术细节)。 注意:内部状态仍然不需要同步,因为 Actors guarantee happens-before semantics 在处理消息之间。

    并行性是通过让多个 Actor 并行工作来实现的,通常形成 supervisor hierarchiesbalancing workload

    请注意,如果您只需要并发/异步计算,但您没有或可以摆脱全局状态,Futures are a better composing 和更简单的概念。

    【讨论】:

    • 不错的答案。我要补充一点,虽然演员的反应可以在不同的线程上运行(因此normally 会受到内存访问问题的影响),但您实际上不需要同步对演员状态的访问。这是因为演员框架在执行演员之前已经这样做了。见stackoverflow.com/questions/1031167/…
    • 很高兴它有帮助。 Régis:谢谢,将文本更新得更准确。
    【解决方案2】:

    “演员”不是多线程的,但演员系统通常是。每个参与者一次只执行一个动作,但是当有多个参与者时,每个参与者都可以并行地对其各自的封装状态进行操作。如果计数器属性未在参与者之间共享,则它不是共享可变状态。

    如果您的问题是关于 Actor 系统的实现,它会有所不同并且通常是可配置的,即默认的 Scala Actor 可以配置为运行单线程或在线程池上或使用 Java ForkJoin 任务。我发现 scala.actors 源代码非常易读,因此如果您想了解发生了什么,我建议您查看一下。

    【讨论】:

    • +1 指向 Scala 源代码的指针。它很好地展示了这个概念。
    【解决方案3】:

    您可以使用单独的演员进行计数。当演员收到消息时,它可以向(单例)计数演员发送消息。这样一来,您就可以拥有多个工作角色并仍然计算消息数。

    Akka 有一个名为 Agents 的东西,在这种情况下可能很有用。

    val counter = Agent(0)
    counter send (_ + 1)
    

    http://doc.akka.io/docs/akka/2.0.2/scala/agents.html

    【讨论】:

    • 代理是为此用例量身定制的。就线程和同步而言,它们的工作方式类似于用于写入的 actor 和用于读取的 AtomicX。
    猜你喜欢
    • 2011-12-21
    • 1970-01-01
    • 2013-03-11
    • 1970-01-01
    • 2015-02-27
    • 2014-11-10
    • 2014-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多