大數據開發-從Scala到Akka併發編程
大數據開發-從Scala到Akka併發編程
[4-1 Scala作業.pdf](file/4-1 Scala作業_UVqqJLwoIp.pdf)
1.遞歸實現瓶蓋,瓶子換酒瓶的算法
1.1 需求描述
每瓶啤酒2元,3個空酒瓶或者5個瓶蓋可換1瓶啤酒。100元最多可喝多少瓶啤酒?(不允許借啤酒)
思路:利用遞歸算法,一次性買完,然後遞歸算出瓶蓋和空瓶能換的啤酒數
1.2 代碼實現
def extralPeer(bot: Int, cap: Int): Int = {
val count = bot / 3 + cap / 5
if (count <= 0)
return 0
val modBot = bot % 3
val modCap = cap % 5
count + extralPeer(count + modBot, count + modCap)
}
2.Scala實現猜拳遊戲
2.1 需求如下
- 選取對戰角色
- 開始對戰,用戶出拳,與對手進行比較,提示勝負信息
- 猜拳結束算分,平局都加一分,獲勝加二分,失敗不加分
- 循環對戰,當輸入“n”時,終止對戰,並顯示對戰結果
- 遊戲結束後顯示得分
2.2 實現邏輯和主要代碼
- 創建用戶類User,定義類的屬性(name,score)和類的方法(showFist())
- 創建計算機類Computer,定義類的屬性(name,score)和類的方法(showFist())
- 實現計算機隨機出拳
- 創建遊戲類Game,定義類的屬性(甲方玩家、乙方玩家、對戰次數)
- 編寫初始化方法、遊戲開始方法
主要代碼:
2.3 效果演示
代碼:https://github.com/hulichao/bigdata-code/tree/master/src/main/scala/com/hoult/scala/job/game
def extralPeer(bot: Int, cap: Int): Int = {
val count = bot / 3 + cap / 5
if (count <= 0)
return 0
val modBot = bot % 3
val modCap = cap % 5
count + extralPeer(count + modBot, count + modCap)
}
3.用戶位置時長統計sql
3.1 需求描述
現有如下數據需要處理: 字段:用戶ID,位置ID,開始時間,停留時長(分鐘)
4行樣例數據: UserA,LocationA,8,60 UserA,LocationA,9,60 UserB,LocationB,10,60 UserB,LocationB,11,80
樣例
數據中的數據含義是: 用戶UserA
,在LocationA
位置,從8點開始,停留了60鍾
處理要求: 1、對同一個用戶,在同一個位置,連續的多條記錄進行合併 2、合併原則:開始時間取最早時間,停留
時長累計求和
3.2 Sql實現
select user_id, location_id, min(start_time) as start_time, sum(stay_time) as stay_time from t1 group by user_id, location_id
4.Actor間通訊
編寫兩個Actor, 分別是AActor和BActor,兩個Actor之間可以互相發送消息
4.1主要實現
先用一個start
命令啓動AActor
,然後給自己發 一個消息,啓動go
後面的流程,然後A,B
互相循環發送消息
主要代碼:https://github.com/hulichao/bigdata-code/tree/master/src/main/scala/com/hoult/scala/job/actor
object Demo {
private val MyFactory = ActorSystem("myFactory")
// 通過MyFactory.actorOf方法來創建一個actor;
//只給A發消息,讓他們兩個Actor開始對話
private val bActorRef = MyFactory.actorOf(Props[BActor], "bAcator")
private val aActorRef = MyFactory.actorOf(Props(new AActor(bActorRef)), "aAcator")
def main(args: Array[String]): Unit = {
var flag = true
while (flag) {
val consoleLine: String = StdIn.readLine()
//通過!來發送消息
aActorRef ! consoleLine
if (consoleLine.equals("拜拜")) {
flag = false
println("程序即將結束!")
}
// 休眠100毫秒
Thread.sleep(100)
}
}
}
5.模擬Spark中Master與Worker進程通訊
https://www.jianshu.com/p/43cf21b424ec
爲了加深對主從服務心跳檢測機制(HeartBeat)的理解,模擬master與slave之間的通信。
- Worker 註冊到 Master,Master 完成註冊,並回復 Worker 註冊成功(註冊功能)
- Worker 定時發送心跳,並在 Master 接收到
- Master 接收到 Worker 心跳後,要更新該 Worker 的最近一次發送心跳的時間
- 給 Master 啓動定時任務,定時檢測註冊的 Worker 有哪些沒有更新心跳,並將其從 hashmap 中刪除
5.1 代碼實現
關鍵點:Worker 和 Master的啓動方式都是 通過發送start來啓動的,協議使用模板類來實現,故增加幾個case class,處理邏輯注意 客戶端要發送哪幾類消息,服務端要接受那幾類消息,兩者結合使用即可,代碼:https://github.com/hulichao/bigdata-code/tree/master/src/main/scala/com/hoult/scala/job/spark
主要實現:
//master消息處理
val workers = mutable.Map[String, WorkerInfo]()
override def receive: Receive = {
case "start" => {
println("master running....")
// 檢查超時worker
self ! StartTimeOutWorker
}
case StartTimeOutWorker => {
println("start check timeout worker...")
// 定義定時器,每隔一段時間檢查worker心跳是否超時
import context.dispatcher
context.system.scheduler.schedule(0 millis, 9000 millis, self, RemoveTimeOutWorker)
}
case RemoveTimeOutWorker => {
// 獲取workers中所有workerInfo
val workerInfos = workers.values
// 獲取當前時間
val currentTime = System.currentTimeMillis()
// 找出超時6秒的worker
workerInfos.filter(info => (currentTime - info.lastHeartBeatTime) > 6000)
.foreach(workers -= _.id)
println(s"===> workers.size = ${workers.size}")
}
case RegisterWorkerInfo(id, cpu, ram) => {
//判斷是否已註冊
if (!workers.contains(id)) {
val info =
// 添加數據
workers += (id -> new WorkerInfo(id, cpu, ram)) //worker列表添加
println("workers => 註冊:" + workers)
//註冊成功回覆消息
sender() ! RegisteredWorkerInfo
}
}
case HeartBeat(id) => {
// 更新對應workinfo的心跳時間
// 從workers中取出workerinfo
val workerInfo = workers(id)
// 更新最後心跳時間
workerInfo.lastHeartBeatTime = System.currentTimeMillis()
println(s"master updated worker ${id}'s heartbeat")
}
//worker消息處理
override def receive: Receive = {
case "start" => {
println("worker running...")
// 發送註冊信息
masterProxy ! RegisterWorkerInfo(id, 16, 16 * 1024)
}
case RegisteredWorkerInfo => {
println(s"worker ${id} registered!")
// 定義定時器,每隔一段時間告訴自己發送心跳
import context.dispatcher
// 0 millis:立即執行
// 3000 millis:每隔3秒執行
// self:接收對象,發給自己
// SendHeartBeat:發送內容
context.system.scheduler.schedule(0 millis, 3000 millis, self, SendHeartBeat)
}
//發送心跳
case SendHeartBeat => {
println(s"worker ${id} send heartbeat to master")
masterProxy ! HeartBeat(id)
}