Showing posts with label actor. Show all posts
Showing posts with label actor. Show all posts

Wednesday, December 9, 2009

Futures

Futures are mainly tokens returned by an actor that promises a result sometime in the future. The typical place one encounters a future is from an actor. The !! method of an actor returns a future. However in addition the Futures object provides several methods for doing parallel processing without having to write actors (or threads for that matter.)

Note: My use of scala.util.Random requires Scala 2.8 but I think the rest is 2.7.7.
  1. scala> import scala.actors.Futures._                
  2. import scala.actors.Futures._
  3. /* 
  4. The most basic future example.  
  5. Just runs the function in a seperate thread and returns a Future object
  6. for the result
  7. */
  8. scala> future {Thread.sleep(10000);println("hi");10}
  9. res2: scala.actors.Future[Int] = < function0>
  10. /* 
  11. Use one of the future methods for obtaining the actual result
  12. this one blocks tile ready, but other can check if result is ready and so on
  13. */
  14. scala> res2()
  15. hi
  16. res3: Int = 10
  17. /*
  18. This is more interesting. 
  19. The method creates several futures and the using the awaitAll method 
  20. waits for all the futures to complete before continuing
  21. */
  22. scala> def bubbles = {                                                                                                             
  23.      | val bubbles = for( i <- 1 to 20) yield {
  24.      |   future {
  25.      |     Thread.sleep(scala.util.Random.nextInt(20)*500)
  26.      |     println("pop "+i)
  27.      |     "pop "+i
  28.      |   }
  29.      | }
  30.      | awaitAll(30000, bubbles:_*) foreach println _                                                                               
  31.      | }
  32. bubbles: Unit
  33. scala> bubbles
  34. pop 9
  35. pop 12
  36. pop 11
  37. pop 5
  38. pop 3
  39. pop 14
  40. pop 20
  41. pop 10
  42. pop 1
  43. pop 4
  44. pop 16
  45. pop 6
  46. pop 7
  47. pop 2
  48. pop 8
  49. pop 18
  50. pop 15
  51. pop 19
  52. pop 17
  53. pop 13
  54. Some(pop 1)
  55. Some(pop 2)
  56. Some(pop 3)
  57. Some(pop 4)
  58. Some(pop 5)
  59. Some(pop 6)
  60. Some(pop 7)
  61. Some(pop 8)
  62. Some(pop 9)
  63. Some(pop 10)
  64. Some(pop 11)
  65. Some(pop 12)
  66. Some(pop 13)
  67. Some(pop 14)
  68. Some(pop 15)
  69. Some(pop 16)
  70. Some(pop 17)
  71. Some(pop 18)
  72. Some(pop 19)
  73. Some(pop 20)
  74. scala> import java.net._                                                                                        
  75. import java.net._
  76. scala> import scala.io._
  77. import scala.io._
  78. /*
  79. A kind of funny example.  We set off two futures to download the google page
  80. and print the first that finishes
  81. */
  82. scala> def load = {
  83.      | val com = future {
  84.      |   val comStream = new URL("http://www.google.com").openStream()                                                                       
  85.      |   Source.fromInputStream(comStream).getLines().mkString("\n")
  86.      | }
  87.      | val ch = future {
  88.      |   val chStream = new URL("http://www.google.ch").openStream()
  89.      |   Source.fromInputStream(chStream).getLines().mkString("\n")
  90.      | }  
  91.      | awaitEither(ch,com)                                                                                               
  92.      | }
  93. load: Any
  94. scala> load
  95. res0: Any = 
  96. & !doctype html...

Wednesday, November 11, 2009

Introduction to Actors

The support for Actors is one of the features that attracts many new developers to Scala. It is not the only concurrancy construct in Scala but it is one of the most recognized.

An actor is essentially an active object. Instead of calling methods on the actor messages are passed to the actor and the message will be handled in a thread. Resources about actors can be found all over the internet a couple pages to look at are:
This is a big topic about how threads are scheduled and so on but for now we will write a simple little program that downloads several webpages in parallel.
  1. scala> import scala.actors.Actor
  2. import scala.actors.Actor
  3. scala> import Actor._
  4. import scala.actors.Actor._
  5. scala>  val collector = actor {
  6.      |   var count = 3
  7.      |   var data = ""
  8.      |   loop {
  9.      |   react { 
  10.      |    case payload:String => {
  11.      |      reply ("thank you")
  12.      |      data += payload + "\n\n"
  13.      |      count -= 1
  14.      |      if (count == 0) {
  15.      |        println (data)
  16.      |        exit()
  17.      |     }
  18.      |    }
  19.      |  }
  20.      | }
  21.      | }
  22. collector: scala.actors.Actor = scala.actors.Actor$$anon$1@2bbef4c6
  23. scala> import scala.io.Source
  24. import scala.io.Source
  25. scala> class Downloader(url:Stringextends Actor {
  26.      |  def act = {
  27.      |   val source = Source.fromURL(new java.net.URL(url))
  28.      |   val data = source.getLines.mkString("\n")
  29.      |   collector ! data
  30.      |   receive { case s => println("Done with "+url) }
  31.      |  }
  32.      | }
  33. defined class Downloader
  34. scala> List("http:/daily-scala.blogspot.com/2009/11/using-objects-as-functions.html",
  35.      |      "http:/daily-scala.blogspot.com/2009/10/boolean-extractors.html",
  36.      |      "http:/daily-scala.blogspot.com/2009/08/java-vs-scala-control-structures.html",
  37.      |      "http:/www.blogger.com/profile/07600430363435495915")
  38. res0: List[java.lang.String] = List(http:/daily-scala.blogspot.com/2009/11/using-objects-as-functions.html, http:/daily-scala.blogspot.com/2009/10/boolean-extractors.html, http:/daily-scala.blogspot.com/2009/08/java-vs-scala-control-structures.html, http:/www.blogger.com/profile/07600430363435495915)
  39. scala> for (url <- res0) { 
  40.      | new Downloader(url).start
  41.      | }
  42. [snip... lots of output]

Update:
If this program is put into a file and executed it will not finish is because the program exits. What is happening is there are 6 "actors" the main thread, collector and the 4 Downloaders. The main thread completes and shutdown the system taking all the Actors with it.

Just add link(collector) as the last line to make the main trhead wait for collector.

Also important to realize is that in Scala 2.7 an actor is lightweight. IE the application can exit while actors are still alive. In Scala 2.8 that is changed. For Scala 2.7 semantics you must use a DaemonActor instead of Actor.