【问题标题】:Parallel collections in Scala 2.9 and ActorsScala 2.9 和 Actors 中的并行集合
【发布时间】:2011-08-02 06:41:34
【问题描述】:

好的,这可能是一个相当愚蠢的问题,但是在参与者框架中使用并行集合有什么好处?也就是说,如果我一次只处理来自参与者邮箱的一条消息,是否还需要并行收集?平行收藏和演员是相互排斥的吗?什么是同时涉及两者的用例?

【问题讨论】:

    标签: scala collections parallel-processing actor scala-2.9


    【解决方案1】:

    他们解决不同的问题。演员擅长解决task parallel problems。而并行集合擅长解决data parallel problems。我不认为它们是相互排斥的——你可以在actors中使用并行集合,也可以在包含actors的并行集合中使用。


    编辑 - 快速测试: 甚至像演员通知循环这样简单的东西也会受益。

    在下面的代码中,我们将一百万个演员注册到一个演员注册表,该注册表必须通知他们一个事件。

    在我的机器(4 核 2.5 GHz 笔记本电脑)上,非并行通知循环 (registry foreach {}) 平均需要 2.8 秒。 当使用并行收集循环 (registry.par.foreach {}) 时,需要 1.2 秒并使用所有四个内核。

    import actors.Actor
    
    case class Register(actor: Actor)
    case class Unregister(actor: Actor)
    case class Message( contents: String )
    
    object ActorRegistry extends Actor{
      var registry: Set[Actor] = Set.empty
    
      def act() {
        loop{
          react{
            case reg: Register => register( reg.actor )
            case unreg: Unregister => unregister( unreg.actor )
            case message: Message => fire( message )
          }
        }
      }
    
      def register(reg: Actor) { registry += reg }
    
      def unregister(unreg: Actor) { registry -= unreg }
    
      def fire(msg: Message){
        val starttime = System.currentTimeMillis()
    
        registry.par.foreach { client => client ! msg } //swap registry foreach for single th
    
        val endtime = System.currentTimeMillis()
        println("elapsed: " + (endtime - starttime) + " ms")
      }
    }
    
    class Client(id: Long) extends Actor{
      var lastmsg = ""
      def act() {
        loop{
          react{
            case msg: Message => got(msg.contents)
          }
        }
      }
      def got(msg: String) {
        lastmsg = msg
      }
    }
    
    object Main extends App {
    
      ActorRegistry.start
      for (i <- 1 to 1000000) {
        var client = new Client(i)
        client.start
        ActorRegistry ! Register( client )
      }
    
      ActorRegistry ! Message("One")
    
      Thread.sleep(6000)
    
      ActorRegistry ! Message("Two")
    
      Thread.sleep(6000)
    
      ActorRegistry ! Message("Three")
    
    }
    

    【讨论】:

    • 感谢您的回答。我可以看到一个 CAN 在参与者中使用并行集合,但在这种情况下,它似乎并不比使用常规集合更有利。另一方面,使用包含演员的并行集合的想法似乎很有用。我喜欢这个主意。谢谢你让我深思……
    • 感谢您创建一些测试代码,太好了!我真的很感激。
    • @布鲁斯。注意这里还有另一个使用并行集合的机会——上面的代码需要大约 12 秒来执行 init 循环。如果我们并行化它大约需要 4 秒( (1 to 1000000).par.foreach{ i => ... } )。
    【解决方案2】:

    Scala 中的 Actors 库只是众多选项(线程和锁、STM、futures/promises)中的一种选项和方法,它不应该用于解决各种问题,也不应该与一切(尽管演员和STM可以一起做很多事情)。在某些情况下,设置一组参与者(工人 + 主管)或明确地将任务分成多个部分,以将它们提供给 fork-join 池,这太麻烦了,调用.par on 更方便您已经在使用的现有集合,只需并行遍历它,几乎可以免费获得性能优势(就设置而言)。

    总而言之,actor 和并行集合是问题的不同维度——actor 是一种并发范式,而并行集合只是一个有用的工具,不应将其视为并发替代方案,而应视为集合的扩充工具集。

    【讨论】:

    • 感谢您对此的看法。这是有道理的。
    猜你喜欢
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多