【问题标题】:Scala Actor Prime SieveScala Actor Prime Sieve
【发布时间】:2012-08-13 11:39:34
【问题描述】:

我是一个新晋的 java 编码员,最近被告知要检查 scala 的并发实现。我想一个简单的(尽管不是最好的说明并发性)示例可能是让演员解决 Eratosthenes 的筛子。到目前为止,我已经拼凑出一些东西,但我不确定我要去的方向是否接近正确。这是我当前的代码:

import scala.actors.Actor
import scala.actors.Actor._
import Array._

class PrimeActor(val id: Int) extends Actor {

     //Runs one Prime of the Sieve of Eratosthenes
     def sieve(p: Int, list: Array[Int]) {
       var i = 1
       var place = 0
       while(list contains (i * p)) {
       place = list.indexOf(i * p)
       if (list(place) != 0) 
          list.update(place, 0)
       i += 1
       }
     }

   //Checks to see if there is a higher prime in the list
   //If so, creates a new actor to handle it and sends
   //it the list and the prime
   def findandCreateNextPrime(p: Int, list: Array[Int]){
      var i = 1
      var place = list.indexOf(p)
      while(list(place + i) == 0 && (p + i) <= list.last) {
         i += 1
      }
      val newP = list(place+i)

      if (list contains (p + i)) {
         if ((p + i) equals list.last) {
            print(list.last)
         } else {
            print(", ")
            val pA = new PrimeActor(newP)
            pA.start()
            pA ! (list(newP), list)
         } 
     } else {
     println("DONE")
    } 
  }

   //Actor behavior
   def act() {
      loop {
         react{
            case (recievedP: Int, recievedList: Array[Int]) =>
               print(recievedP)
               sieve(recievedP, recievedList)
               findandCreateNextPrime(recievedP, recievedList)
               exit()
         }
      }
   }
}

任何帮助或方向输入将不胜感激。谢谢!

【问题讨论】:

    标签: scala actor primes


    【解决方案1】:

    在 Scala 中,您可以以函数式风格编写代码。我建议你使用它。首先忘记Array,它是一个可变集合,Scala 中的可变集合是邪恶的。最好使用不可变集合作为Listvar也是一样。尽可能使用val
    我猜想,在 Scala 中实现 Eratosthenes 筛的最简单方法如下:

    import scala.annotations.tailrec
    
    def sieve(until: Int): Seq[Int] = {
      @tailrec
      def loop(i: Int, primes: Seq[Int]): Seq[Int] = {
        // we reached the desired end
        if (i > until) primes
        else {
          // we already found a factor of this i
          if (primes exists(i % _ == 0)) loop(i + 2, primes)
          // we found a new prime
          else loop(i + 2, primes :+ i)
        }
      }
      // there is no prime smaller than 2
      if (until < 2) Seq.empty[Int]
      // starting with 3 has the advantage, we only need to check i + 2
      else loop(3, Seq.empty[Int] :+ 2)
    }
    

    如果您刚开始使用 Scala,这可能有点令人困惑,但我会解释一下。
    我们想要一个由所有素数组成的序列,直到一个特定的数字。我们定义了一个递归函数,它将检查每隔一个数字是否为素数。因为它是尾递归的,编译器会将其优化为便于理解,所以我们不需要为StackOverflows 操心。如果我们的计数器超过最大值 (until),我们返回质数,我们检测到。这是我们的递归锚。否则,我们检查我们是否找到了一个素数,这是我们当前i 的一个因素。如果有,我们就跳到下一个候选者,否则我们将i 添加到我们的素数并继续下一个候选者。
    注意:注解不是必须的,但如果它存在,编译器会警告你,如果函数不是尾递归的。

    使用我建议的代码会导致我们遇到问题,您不能再使用并发性了。 Scala 中的并发性的一个很好的介绍,是来自Programming Scala 的一章。他们通过并发解决了睡觉的理发师问题。这是他们解决方案的link

    【讨论】:

      【解决方案2】:

      Actor 是关于并发性的:不同的任务同时完成,必要时相互通信。

      关于演员有两点非常重要:

      1. 您只能通过消息与演员交谈。如果您的演员没有在返回时发回消息,或者从消息以外的其他地方获取信息,那么您做错了。
      2. 您不向参与者发送可变数据结构。如果你这样做了,那你就做错了。

      因此,您在示例中打破了这两个规则,并且演员之间实际上没有互动。由于这些原因,演员在这里可能是错误的选择。在这种情况下,最好查看并行集合以获得答案,但在这里它们也无济于事。

      埃拉托色尼筛法本质上是一种串行算法,对于并行性或并发性来说都是一个糟糕的选择。

      【讨论】:

      • 一旦找到素数p,为什么不启动一个单独的工作人员沿着数组移动并将每个p-th 数字标记为非素数,就像筛子必须做的那样?传达每个工人的进度是否有困难,以便主人不会领先于他们中的任何一个?收益是不是太小了?我是站在完全无知的立场上发言的。但我预计筛子实际上是并发的良好候选者: P = {3,5, ...} \ U {{p^2, p^2 +2p,...} | p in P} 加上2.
      • @WillNess 不允许主人领先于其他参与者正在做的事情存在同步问题,但更重要的是,您如何使用其他参与者的结果?如果你每一个都去问,那太贵了。如果您需要合并结果,这比首先计算它们更昂贵。
      • 他们不能在 one 可相互访问的可变数组上工作吗?这里可以只做一个例外吗?实际上,这个被筛分的数组他们的通信设备(记录每个数组的进展结果)......他们不从它读取,只有写给它,这可能有助于允许吗? master 期望每个 worker 只收到两条消息:1. 完成了第一步 2. 完成。
      • @WillNess 不,他们不能。 Actor 不能共享可变状态。如果他们这样做,他们就不是演员。请注意,我在这里不是一个口无遮拦的铁杆纯粹主义者。但是,如果您确实共享可变状态,那么您就不是在做演员,您只是在做多线程,在代码和线程之间有一个沉重的间接层。 除此之外,让多个线程更新同一个数组会大量消耗你的 CPU 缓存,因此单线程解决方案肯定会更快。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      • 1970-01-01
      • 1970-01-01
      • 2012-02-23
      • 2014-11-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多