geotrellis使用(六)Scala並發(並行)編程


      本文主要講解Scala的並發(並行)編程,那么為什么題目概稱geotrellis使用(六)呢,主要因為本系列講解如何使用Geotrellis,具體前幾篇博文已經介紹過了。我覺得干任何一件事情基礎很重要,就像當年參加高考或者各種考試一樣,老師都會強調基礎,這是很有道理的。使用Geotrellis框架的基礎就是Scala和Spark,所以本篇文章先來介紹一下Scala編程語言,同樣要想搞明白Scala並發(並行)編程,Scala基礎也很重要,沒有Scala語言基礎就談不上Scala並發編程也就更談不上使用Geotrellis或者Spark,本文先簡單介紹一下Scala基礎知識,這方面的書籍或者文章很多,大家可以網上找一下。

一、Scala基礎     

      關於Scala基礎最主要的就是模式匹配,這造就了整個Scala語言靈活方便的特點,通俗的說模式匹配就是其他語言中的switch case,但是其實功能要遠遠復雜的多,涉及到樣本類(case class)、unapply函數等具體網上有很多介紹。其次還有強大的for表達式、偏函數、隱式轉換等,下面主要為大家介紹Scala並發(並行)編程。

二、SBT簡介    

      使用Scala語言編程,最好使用SBT框架,可以自動幫你完成包管理等,相當於java中的maven,下面先簡單介紹一下SBT基礎。

      首先安裝SBT,很簡單,只需要下載安裝包即可(http://www.scala-sbt.org/release/docs/Installing-sbt-on-Windows.html),具體安裝過程以及配置等,大家也可以在網上找的到。安裝完成之后,在IDEA中安裝sbt插件,然后選擇創建SBT項目,與普通Scala語言最主要的不同是會創建一個build.sbt文件,這個文件主要記錄的就是項目的依賴等,要添加依賴就可以添加如下兩行代碼:

libraryDependencies +=  "com.typesafe.akka" % "akka-actor_2.11" % "2.4.4"

resolvers += "Akka Snapshot Repository" at "http://repo.akka.io/snapshots/"

      其實build.sbt文件是一個被SBT直接管理的scala源文件,里面的語句均要符合Scala語法,其中libraryDependencies和resolvers 是定義好的Key,+= % at等都是寫好的方法。libraryDependencies是存儲系統依賴的Key,該語句添加了一個ModuleID對象,"com.typesafe.akka"為groupID,"akka-actor_2.11"為artifactID,2.4.4"為revision,%方法最終就創建了一個ModuleID對象,此處需要注意_2.11表示當前的Scala版本。resolvers表示系統如何能夠找到上面的libraryDependencies,at 方法通過兩個字符串創建了一個 Resolver 對象,前者為名稱,后者為地址。一般lib的官網中均會有寫明自己的上述語句供使用者方便添加自己lib依賴。

三、並發編程     

     下面為大家介紹如何使用Scala進行並發編程。

1、原生支持

     Scala語言原生支持並發編程,只需要使類繼承scala.actors.Actor即可,復寫父類的act方法,也可以直接建立一個匿名類,直接使用actor{}即可,其中receive是一個偏函數,用於接收並處理其他Actor發送的消息,這里就用到了模式匹配,可以根據不同的消息類型進行不同的處理,相當於路由。

 1 object ActorTest2 extends App {
 2   val actor_a: Actor = actor{
 3     while (true){
 4       receive {
 5         case msg => println("actor_a   " + msg)
 6       }
 7     }
 8   }
 9 
10   val actor_b = actor{
11     while (true){
12       receive {
13         case msg => {
14           println("actor_b   " + msg)
15           actor_a ! "b  ---- >>>  a" 
16           sender ! "receive  " + msg
17         }
18       }
19     }
20   }
21 
22   actor_a ! "wsf"
23   actor_b ! Math.PI
24 }

      上面的代碼定義了兩個Actor對象actor_a,actor_b,采用此種方式Actor會自動start,然后在主線程中各向每個Actor發送了一條信息,Actor接收到信息后進行簡單的打印操作。由於Scala已經廢棄了此種方式來進行並發編程,在這里也只是簡單介紹,下面我們來看一下如何通過使用akka來進行並發編程。

2、akka

      akka是一個簡單易用的Scala並發編程框架(網址:http://akka.io/),其宗旨就是"Build powerful concurrent & distributed applications more easily."。引入akka只需要在build.sbt文件中添加在SBT操作一節中介紹的代碼即可,但是要根據自己的Scala版本以及要使用的akka版本進行修改。添加完之后IDEA會自動去下載akka的actor包。其使用基本與原生actor相同,同樣創建一個類繼承akka.actor.Actor,復寫其receive方法。其代碼如下:

1 class MyActor extends Actor{
2   override def receive={
3     case message: String=> println(message)
4     case _ => unhandled()
5   }
6 }

      與原生Actor不同的是akka為其Actor加入了path的概念,即每個Actor都有一個絕對路徑,這樣系統首先要創建一個system,然后在system創建其下的Actor,代碼如下:

val system = ActorSystem("akkatest")

val actor = system.actorOf(Props(classOf[wsf.akkascala.MyActor]), "akkaactor")

      其中ActorSystem("akkatest")即創建一個akka的system,用於管理Actor,第二句就是在system中創建一個上面MyActor實例。通過打印actor.path可以得到akka://akkatest/user/akkaactor,可以看出該Actor確實是在system之下,其中user表示是用戶自定義Actor。

      Actor實例創建之后無需start,會自動啟動,可以使用actor ! "hello actor"語句來向actor發送消息,MyActor的receive方法接收到該語句之后進行模式匹配,如果能夠匹配上就行進行相應的處理。

      由於Actor具有了路徑,其也就能夠創建屬於自己的Actor實例,只需要在當前Actor類中添加如下代碼:

val otherActor = context.actorOf(Props(classOf[OtherActor]), "otheractor")

      其中OtherActor是定義好的另一個Actor,打印otherActor.path可以得到如下效果:akka://akkatest/user/akkaactor/otheractor,這就表明確實在MyActor中創建了一個子Actor。MyActor就可以管理OtherActor的實例。

      以上介紹了akka的並發編程,其並行編程要稍作修改。

      首先建立一個RemoteActor項目,將build.sbt中項目的引用改為libraryDependencies ++= Seq("com.typesafe.akka" % "akka-actor_2.11" % "2.4.4","com.typesafe.akka" % "akka-remote_2.11" % "2.4.4"),可以看出相比普通Actor項目只是添加了一個akka-remote引用。然后新建一個RemoteActor類同樣繼承自Actor,與普通Actor毫無區別。然后創建一個主類啟動該Actor。唯一需要注意的就是要在resources文件夾中新建一個application.conf文件,該文件是系統的配置文件,里面添加如下代碼:

 1 akka {
 2   loglevel = "INFO"
 3   actor {
 4     provider = "akka.remote.RemoteActorRefProvider"
 5   }
 6   remote {
 7     enabled-transports = ["akka.remote.netty.tcp"]
 8     netty.tcp {
 9       hostname = "127.0.0.1"
10       port = 5150
11     }
12     log-sent-messages = on
13     log-received-messages = on
14   }
15 }

      主要定義使用tcp協議的方式進行數據傳輸,端口是5150。這樣就完成了remoteActor的定義。

      然后新建一個LocalActor項目,同樣修改build.sbt文件中的內容如上,然后新建一個LocalActor類,由於此處需要向RemoteActor發送消息,所以必須建立一個RemoteActor的子Actor,具體命令如下:

val remoteActor = context.actorSelection("akka.tcp://remoteSys@127.0.0.1:5150/user/remoteactor")

     其中akka://remoteSys/user/remoteactor是RemoteActor通過system創建的路徑,此處與之不同的是akka后添加.tcp表示通過tcp方式創建然后就是remoteSys后通過@127.0.0.1:5150指定遠程actor的IP地址以及端口。這樣就可建立一個remoteActor的實例,可以通過該實例向remoteActor發送消息。

     LocalActor中也需要添加application.conf文件,但是只需要添加如下語句即可:

1 akka {
2   actor {
3     provider = "akka.remote.RemoteActorRefProvider"
4   }
5 }

四、總結

      本文為大家簡單介紹了scala基礎、sbt簡單操作、原生actor、akka的並發以及並行方式actor,這些是我在學習Geotrellis的過程中學習基礎知識的一部分經驗總結和梳理,只有打好基礎才能更好的拓展自己的知識。要知其然並知其所以然。明白了這些對閱讀Geotrellis源代碼以及Spark源代碼都會有很大的幫助。

五、參考鏈接

一、geotrellis使用初探
二、geotrellis使用(二)geotrellis-chatta-demo以及geotrellis框架數據讀取方式初探
三、geotrellis使用(三)geotrellis數據處理過程分析
四、geotrellis使用(四)geotrellis數據處理部分細節
五、geotrellis使用(五)使用scala操作Accumulo
六、geotrellis使用(六)Scala並發(並行)編程

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM