【问题标题】:How to handle concurrent access to a Scala collection?如何处理对 Scala 集合的并发访问?
【发布时间】:2012-01-05 13:26:02
【问题描述】:

我有一个 Actor,它本质上是维护一个对象列表。它具有三个基本操作,添加、更新和删除(有时删除是从 add 方法调用的,但除此之外),并且适用于单个集合。显然,该后备列表是同时访问的,添加和删除调用不断相互交错。

我的第一个版本使用了 ListBuffer,但我在某处读到它不适合并发访问。我没有遇到并发访问异常,但我确实注意到从中查找和删除对象并不总是有效,可能是由于并发性。

我正在重写它以使用 var List,但从 Scala 的默认不可变 List 中删除项目有点痛苦 - 我怀疑它是否适合并发访问。

那么,基本问题:在并发访问的情况下我应该使用什么集合类型,它是如何使用的?

(也许次要:Actor 实际上是一个多线程实体,还是这只是我的错误概念,它是否在单个线程中一次处理一个消息?)

(Tertiary:在 Scala 中,哪种集合类型最适合插入和随机访问(删除/更新)?)

编辑:致好心的回复者:对不起,我的回复太晚了,我养成了在 SO 或邮件列表上转储问题的坏习惯,然后继续处理下一个问题,暂时忘记了原来的问题。

【问题讨论】:

  • 演员一次处理一条消息。与actor的并发来自异步消息处理,而不是来自一个actor同时处理多条消息。
  • 您要解决的业务问题是什么?
  • @ViktorKlang:我会试着解释一下。用户通过 REST 服务向服务器发送一个称为 NotificationPlan 的模型对象。根据 NotificationPlan,会生成许多 Notification 对象,这些对象将在未来某一时刻被发送回用户(以 Apple 推送通知的形式)。在这种情况下,具有问题中描述的列表的参与者在内存中维护了一个 NotificationPlans 列表,以便用户在最初添加它之后可以更新或删除他的计划。

标签: scala collections concurrency


【解决方案1】:

Scala 的不可变集合适合并发使用。

至于演员,如here Akka 文档所述,有几件事得到保证。

  • 参与者发送规则:向参与者发送消息发生在接收同一参与者之前。
  • actor 后续处理规则:其中一条消息的处理发生在同一actor 处理下一条消息之前。

您不能保证同一个线程处理下一条消息,但您有保证当前消息将在下一条消息开始之前完成处理,并且在任何给定时间,只有一个线程正在执行接收方法。

这样就可以处理给定 Actor 的持久状态。关于共享数据,据我所知,最好的方法是使用不可变数据结构并尽可能依赖 Actor 模型。即“不要通过共享内存进行通信;通过通信来共享内存”。

【讨论】:

    【解决方案2】:

    您不需要同步参与者的状态。 Actor 的目的是避免复杂、容易出错和难以调试的并发编程。

    Actor 模型将确保 Actor 会一一消费消息,并且您永远不会有两个线程消费同一 Actor 的消息。

    【讨论】:

      【解决方案3】:

      在并发访问的情况下应该使用什么集合类型,如何使用?

      查看@hbatista 的回答。

      Actor 实际上是一个多线程实体,或者这只是我的错误概念,它是否在单个线程中一次处理一个消息

      第二个(虽然处理消息的线程可能会改变,所以不要在线程本地数据中存储任何东西)。这就是参与者如何保持其状态的不变量。

      【讨论】:

        【解决方案4】:

        看看 scala.collection.mutable.Synchronized* 特征/类。

        想法是将 Synchronized 特征混合到常规可变集合中以获得它们的同步版本。

        例如:

        import scala.collection.mutable._
        val syncSet = new HashSet[Int] with SynchronizedSet[Int]
        val syncArray = new ArrayBuffer[Int] with SynchronizedBuffer[Int]
        

        【讨论】:

        • 请不要这样做,它不会扩展。
        • 从 Scala 2.11 开始,不推荐使用 SyncronizedSet:不推荐使用通过特征进行同步,因为它本质上是不可靠的。考虑 java.util.concurrent.ConcurrentHashMap[A,Unit] 作为替代方案。
        猜你喜欢
        • 2012-01-26
        • 2018-02-21
        • 2019-12-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-31
        • 1970-01-01
        • 2012-08-23
        相关资源
        最近更新 更多