Scala演员Prime Sieve

时间:2012-08-13 11:39:35

标签: scala actor primes

我是一个新的java编码器,最近被告知检查scala的并发实现。我认为一个简单的(虽然不是最好的说明并发)例子可能是让演员解决Eratosthenes的Sieve。我已经拼凑了一些东西,但是我不确定我的方向是否接近正确。这是我目前的代码:

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()
         }
      }
   }
}

非常感谢任何帮助或方向输入。谢谢!

2 个答案:

答案 0 :(得分:4)

在Scala中,您可以用函数式编写代码。我建议你使用它。首先忘掉Array,它是一个可变的集合,scala中的可变集合是邪恶的。最好将不可变集合用作List。关于var也是如此。尽可能使用val。 我可以猜测,在斯卡拉实施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,这可能会让人感到困惑,但我会解释。 我们想要一个所有素数的序列,直到一个特定的数字。我们定义了一个递归函数,如果它是素数,它将检查每一个数字。因为它是尾递归的,所以编译器会将它理解为for-comprehension,所以我们不需要为StackOverflow而烦恼。如果我们的计数器超过最大值(until),我们会返回素数,我们检测到。这是我们的递归锚。否则我们检查我们发现了一个素数,这是我们的一个因素i。如果有一个,我们只是跳到下一个候选者,否则我们将i添加到我们的素数中并继续下一个候选者。
注意:注释不是必需的,但是如果它存在,编译器在警告你的时候,如果函数不是tailrecursive。

使用我建议的代码导致我们解决问题,你不能再使用concurency了。关于scala的可靠性的一个很好的介绍是Programming Scala的一章。他们通过精确解决了睡觉的理发师问题。这是他们解决方案的link

答案 1 :(得分:0)

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

演员有两个非常重要的事情:

  1. 您只能通过消息与演员交谈。如果你的演员没有通过回复发回消息,或者从消息以外的地方获取信息,那你就错了。
  2. 您不向演员发送可变数据结构。如果你这样做,你做错了。
  3. 所以,你在你的例子中打破了两个规则,并且演员之间真的没有互动。由于这些原因,演员在这里可能是错误的选择。在这种情况下,看一下并行集合的答案可能会更好,但它们也不会对你有帮助。

    Eratosthenes的Sieve是一种固有的串行算法,对于并行或并发来说是一个糟糕的选择。