scala并发编程

使用actor并发

    scala的actor提供了一种基于事件的轻量级线程。只要使用scala.actors.Actor伴生对象的actor()方法,就可以创建一个actor。它接受一个函数值/闭包做参数,一创建好就开始运行。用!()方法给actor非诉讼消息,用receive()方法从actor接受消息。receive()可以闭包为参数,通常用模式匹配处理接收到的消息。

def sumOfFactorsInRange(lower: Int,upper:Int, number:Int) = {
	    var sum = 0
		for (i <- lower to upper) {
		  if (number % i == 0)  sum += i
		}
	    sum
	}
	
	def isPerfectConcurrent(candicate: Int) = {
	    val range = 10000
	    val partitions = (candicate.toDouble / range).ceil.toInt
	    val caller = self//主线程
	    for (i <- 0 until partitions) {
	      val lower = i * range + 1
	      val upper = candicate.min(i + 1) * range
	      actor {
	        //发送消息
	        caller ! sumOfFactorsInRange(lower, upper, candicate)
	      }
	      
	    }
	    val sum = (0 /: (0 until partitions)) {(partialsum ,i) =>
	       receive {
	         //接受,并采用模式匹配
	         case sumInRange: Int => partialsum + sumInRange
	       }
	    }
	    2 * candicate == sum
}

消息传递

    每个actor都有自己的消息队列,它从InputChannel[Any]接收输入,通过OutputChannel[Any]发送输出。这些消息顺序的存在队列中。发送消息时,actor不会阻塞,不过调用receive方法时,actor就会阻塞在那里。

package com.fanshadoop.thread
import scala.actors.Actor._

object MessagePass {
    def main(args:Array[String]) = {
      var starttime: Long = 0
      val caller = self
	  val engossedActor = actor {
	  	println("number  of message recievieds so far" + mailboxSize)
	  	caller ! "send"
	  	Thread.sleep(3000)
	  	println("number  of message recievies while was busy" + mailboxSize)
	  	
	  	receive {//接收消息,actor调用此方法之前一直阻塞
	  	  case msg => 
	  	    val time = System.currentTimeMillis() - starttime
	  	    println("received  message " + msg + " after"+ time)
	  	}
	  	//向调用者发送消息
	  	caller ! "mail loop I received"
	  }
	
	  receive {
	    case _ => println("main loop received message" + mailboxSize)
	  }
	  println("send message")
	  starttime = System.currentTimeMillis()
	  engossedActor ! "hello buddy"
	  val endtime = System.currentTimeMillis() - starttime
	  printf("take less then %dms to send message\n",endtime)
	  Thread.sleep(3000)
	  receive {
	    case msg: String => println("main loop received message" + mailboxSize)//一直阻塞,直到等到消息
	  }
    }
	
}

Actor类

如果想在actor启动时显式控制,希望在actor里存入更多信息,可以创建一个对象,混入actor trait。

package com.fanshadoop.thread

import scala.actors.Actor
import Actor._

object AnswerService {
	class Service(val forks: String*) extends Actor {
	   def act() {
	      while (true) {
	        receive {
	          case (caller: Actor, name : String, message:String) => 
	            caller ! (
	                if (forks.contains(name))  String.format("Hey %s got message %s", name, message)
	                else String.format("Hey there is not any message with name %s", name)
	            )
	          case "ping" => println("ping");
	          case "exit" => println("exit");
	               System.exit(0) 
	        }
	      }
	   }
	}
	
  def main(args: Array[String]): Unit = {
    val serive = new Service("sara", "kara", "john")
    val caller = self
    serive ! (self, "sara", "hello")
    serive ! "ping"
    serive.start
    serive ! "ping"
    serive ! (self, "kara", "hello john")
    serive ! "exit"
    for (i <- 0 to 3) {
      receive {
        case msg : String => println("get response" + msg)
        case _ => println("nothing")
      }
    }
  }

}

    在实现类里,必须实现act方法(在Actor trait中act方法时抽象的)。actor没有启动,发送的消息会进入队列,等待后续处理。

actor方法

与actor交互的顺序是没有任何保证的,actor接收到的消息可以进行处理,只要准备好就可以应答。actor对消息的接受和处理没有预先强加的顺序。

package com.fanshadoop.thread

import scala.actors.Actor
import Actor._

object PrimeTeller {

  def isPrimer(number: Int) = {
    println("going to find number is primer")
    var result = true
    if (number == 2 || number == 3) result = true
    for (i <- 2 to Math.sqrt(number.toDouble).floor.toInt; if result) {
      if (number % i == 0) result = false
    }
    println("going to find number " + number + " is primer " + result)
    result
  }

  def main(args: Array[String]): Unit = {
    val teller = actor {
      var continue = true
      while (continue) {
        receive {
          case (caller: Actor, number: Int) => caller ! (number, isPrimer(number))
          case "quit" => continue = false
        }
      }
    }
    
    teller ! (self, 5)
    teller ! (self, 19)
    teller ! (self, 23)
    
    for (i <- 0 to 2) {
      receive {
        case (number, result) => println(number + " is primer? "+ result)
      }
    }
    
    teller ! "quit"
  }

}

recieve和recieveWithin方法

    receive()方法接收一个函数值/闭包,返回一个处理消息的应答。

package com.fanshadoop.thread
import scala.actors.Actor
import Actor._

object Receive {

  def main(args: Array[String]): Unit = {
     val caller = self
     val accumulator = actor {
        var sum = 0
        var continue = true
        while (continue) {
           sum += receive {
             case number:Int => number
             case "quit" => continue = false;0
             
           } 
        }
        caller ! sum
     }
     
     accumulator ! 1
     accumulator ! 2
     accumulator ! 10
     accumulator ! "quit"
     receive {
       case result => println("total sum is " + result)
     }             
  }

}
    receive()方法会造成阻塞,直到实际接收到应答为止。receiveWithin()方法修正了这一点,它会接收一个timeout参数。
package com.fanshadoop.thread
import scala.actors._
import Actor._

object Receive {

  def main(args: Array[String]): Unit = {
     val caller = self
     val accumulator = actor {
        var sum = 0
        var continue = true
        while (continue) {
           sum += receiveWithin(1000) {
             case number:Int => number
             case TIMEOUT => continue = false;0
             
           } 
        }
        caller ! sum
     }
     
     accumulator ! 1
     accumulator ! 2
     accumulator ! 10
     accumulator ! "quit"
     receiveWithin(1000) {//保持主线程能然活着
       case result:Int => println("total sum is " + result)
       case TIMEOUT => println("timeout")
     }
              
  }

}

    在给定的超时期限内,如果什么都没有收到,receiveWithin()方法会收到一个TIMEOUT消息。如果不对其进行模式匹配,就会抛出异常。

react和reactWithin方法

    在每个actor里,调用receive()的时候实际上会要求有一个单独的线程。这个线程会一直持有,知道这个actor结束。即使在等待消息到达,程序也会持有这些线程。如果在调用序列里没有需要保持和返回的状态,scala机会就可以从线程池里获取任意线程执行消息处理,这就是react()所做的事情。

    react()不同于其表亲receive(),它不返回任何结果。调用receive()后,就回执行紧跟着这个调用的代码。不过react()则不同,放在调用后的任何代码都是不可达的。把调用react()想象成调用它的线程在调用之后就回立即释放。接收到一个消息后,如果可以匹配到react()方法里一个case语句,就会从线程池分配一个线程,执行这个case体。这个线程会一直运行,直到有另一个react()调用,或者是case语句中么有代码可执行了,此时线程返回,处理其他消息,或是去做虚拟机分配的其他任务。

package com.fanshadoop.thread

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


object React {
  def info(msg:String) = println(msg + "recieved by " + Thread.currentThread())
  
  def recieveMessage(id:Int) = {
     for (i <- 1 to 2) {
       receiveWithin(1000) {
         case msg:String => info("msg"+id)
         case TIMEOUT => println("timeout")
       }
     } 
  }
  
  def reactMessage(id:Int) = {
     for (i <- 1 to 2) {
       react {
         case msg:String => info("msg"+id)
         
       }
       println("-------------------")//代码不可达
     } 
  }
  
  
  def main(args: Array[String]): Unit = {
      val actors = Array(
          actor {info("react 1 message created");reactMessage(1)},
          actor {info("react 2 message created");reactMessage(2)},
          actor {info("receive 3 message created");recieveMessage(3)},
          actor {info("receive 4 message created");recieveMessage(4)}
          )
      Thread.sleep(2000)
      for (i <- 0 to 3) {
        actors(i) ! "hello";Thread.sleep(2000)
      }
      Thread.sleep(2000)
      for (i <- 0 to 3) {
        actors(i) ! "hello";Thread.sleep(2000)
      }
  }

}

loop和loopwhile

    相比于在reactWithin()里递归的调用方法,可以在loop()调用里放一个对reactWithin()的调用。执行loop方法的线程遇到reactWithin的调动时,会放弃控制。消息到达时,任意的线程都可以继续执行适当的case语句。case语句执行完毕,线程会继续回到loop块的顶部。这会一直继续下去。loopwhile方法时类似的,但只有提供的参数是有效的,它才会继续循环。

    因为loopwhile方法负责处理循环,可以把局部状态放到循环之外,在reactwithin方法里访问它。这样既可以像receiveWithin那样处理状态,又可以像reactwithin那样利用来自线程池的线程

控制线程执行

    使用receive时,每个actor运行在自己的线程里,react让actor共享来自线程池的线程。通过SingleThreadedScheduler,可以让scala在主线程里运行actor。

package com.fanshadoop.thread

import scala.actors.Actor
import scala.actors.scheduler.SingleThreadedScheduler


trait RunInMainThread extends Actor {  
   override def scheduler() = {
     new SingleThreadedScheduler
   }
}

class MyActor1 extends RunInMainThread {//在主线程中运行
	def act() = {
		println("MyActor1 running in " + Thread.currentThread())
	}
}

class MyActor2 extends Actor {//在自己的线程中运行
    def act() = {
    	println("MyActor2= running in " + Thread.currentThread())
	} 
}

object InMainThread {

  def main(args: Array[String]): Unit = {
    println("Main= running in " + Thread.currentThread())
    new MyActor2 start
    
    new MyActor1 start
    
  }

}

在各种接受方法中的选择

    首先应该优先使用Within结尾的方法,而不是其他的方法。调用receive()或react()可能会导致失败,actor可能会为一个接受不到的消息永远等下去,因为发消息的actor可能已经退出。因此,使用receivewithin或reactwithin,以便在一段合理的时间内没有收到响应之后,能够优雅的恢复过来。

    


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 《Scala函数式编程》是一本非常实用的Scala编程书籍,旨在教读者如何使用Scala编程语言实现函数式编程。该书通过具体的实例和案例来阐述Scala函数式编程的核心概念和技术,包括函数式编程基础、函数的高阶抽象、类型系统、模式匹配、并发编程、I/O 和异常处理等方面内容。这些知识点包含了Scala编程语言的重要概念,可以帮助读者深入掌握Scala函数式编程的技术,并在实际应用中运用它们。此外,该书也涵盖了Scala代码风格和整洁性等方面,对编成良好的代码有很大的帮助。总之,这本书对于学习Scala函数式编程的人来说是非常有实践价值的一本书籍。 ### 回答2: Scala函数式编程的PDF是一本非常有价值的学习资料。对于想要深入学习Scala函数式编程的开发者,这本书提供了全面详尽的指导和实践经验,帮助开发者理解函数式编程的核心概念和思想,并将其应用于Scala程序开发中。 该书主要包括以下内容: 1.函数式编程的基本概念和原则,如不可变性、高阶函数、currying、尾递归等等。 2.函数式数据结构和算法的实现,包括列表、栈、队列、树、图等等。 3.如何使用Scala语言支持函数式编程的特性,如case class、模式匹配、参数化类型、协变和逆变等等。 4.如何使用Scala函数式编程框架,如Akka、Spark等来构建高效的分布式应用。 这本书主要适合已经有一定Scala编程基础或者其他函数式编程语言经验的开发者阅读,由于书中的内容较为深入和专业,对于初学者不太友好。但对于有一定基础的Scala开发者来说,该书是一本非常有价值的参考资料,可以帮助他们更深入地理解Scala函数式编程,提高代码质量和开发效率。 ### 回答3: Scala是一种支持函数式编程范式的编程语言,从而满足了编程语言发展中对于高度抽象和复杂数据处理的需求。Scala函数式编程pdf是一个学习Scala函数式编程理论和实践的重要资源。 Scala函数式编程pdf包含Scala函数式编程核心概念和技术,例如高阶函数、不可变性、模式匹配和递归等。它还涵盖了Scala函数式编程中的一些常见问题和解决方案,以及Scala函数式编程如何与面向对象编程 (OOP)相融合等。 Scala函数式编程pdf还提供了丰富的实际案例,包括使用Scala函数式编程技术实现算法、数据处理、Web应用程序、分布式编程等等。 总之,Scala函数式编程pdf是Scala程序员学习和实践函数式编程的重要资源,它提供了理论、实践和案例相结合的综合性学习体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值