Scala编程基础(八)-- Actor实现WordCount

使用Actor实现WordCount

需求:

用actor并发编程写一个单机版的WordCount,将多个文件作为输入,计算完成后将多个任务汇总,得到最终的结果。

大致的思想步骤:

  • 通过loop +react 方式去不断的接受消息
  • 利用case class样例类去匹配对应的操作
  • 其中scala中提供了文件读取的接口Source,通过调用其fromFile方法去获取文件内容
  • 将每个文件的单词数量进行局部汇总,存放在一个ListBuffer中
  • 最后将ListBuffer中的结果进行全局汇总。

主要用到的知识点:

通过样例类来接收消息和返回消息
例:case class ResultTask(result: Map[String, Int])

flatMap函数 实现分割后压扁
例:lines.flatMap(x => x.split(" "))

map函数初始化次数,构建元组
例:words.map(word => (word, 1))

groupBy函数进行分组
例:wordAndOne.groupBy(x => x._1)

mapValues函数进行相同的key次数统计
例:groupByWord.mapValues(x => x.length)

filter函数过滤有效值
例:futureSet.filter(x => x.isSet)

类型转换
例:value.asInstanceOf[ResultTask]

foldLeft函数求和计算
例:x.foldLeft(0)((x, y) => x + y._2)

具体代码如下:

import scala.actors.{Actor, Future}
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.io.Source

case class SubmitTask(fileName: String)

case class ResultTask(result: Map[String, Int])

//todo:通过scala中actor来实现多个文件单词统计的结果
class Task extends Actor {

  override def act(): Unit = {
    loop {
      react {
        case SubmitTask(fileName) => {
          //1.读取文件内容
          val data: String = Source.fromFile(fileName).mkString
          println(data)
          //运行结果:
          //hello dog
          //cat small

          //2.按照换行符进行切分 windows下换行符\r\n  linux下换行符是\n  mac是\r
          val lines: Array[String] = data.split("\r\n")
          println(lines.toBuffer)
          //运行结果:ArrayBuffer(hello dog, cat small)

          //3.切分每一行获取所有的单词
          val words: Array[String] = lines.flatMap(x => x.split(" "))
          println(words.toBuffer)
          //运行结果:ArrayBuffer(hello, dog, cat, small)  这里使用flatMap是分割后再压扁

          //4.每个单词计数为1
          val wordAndOne: Array[(String, Int)] = words.map(word => (word, 1))
          println(wordAndOne.toBuffer)
          //运行结果:ArrayBuffer((hello,1), (dog,1), (cat,1), (small,1))

          //5.按照单词进行分组
          val groupByWord: Map[String, Array[(String, Int)]] = wordAndOne.groupBy(x => x._1)
          for ((k, v) <- groupByWord) println(k + " -> " + v.toBuffer)
          //运行结果:
          //cat -> ArrayBuffer((cat,1))
          //dog -> ArrayBuffer((dog,1))
          //small -> ArrayBuffer((small,1))
          //hello -> ArrayBuffer((hello,1))

          //6.统计单词出现的次数
          val result: Map[String, Int] = groupByWord.mapValues(x => x.length)
          println(result)
          //运行结果:
          //Map(cat -> 1, dog -> 1, small -> 1, hello -> 1)

          //7.通过sender把结果数据返回回去
          sender ! ResultTask(result)
        }
      }
    }
  }

}

object WordCount {

  def main(args: Array[String]): Unit = {

    //定义一个Set集合,用于保存每一个文件所产生的Future
    val futureSet: mutable.HashSet[Future[Any]] = new mutable.HashSet[Future[Any]]()

    //定义一个list集合,用户保存每一个future中的结果数据
    val resultList: ListBuffer[ResultTask] = new ListBuffer[ResultTask]

    //准备数据文件
    val files = Array(
      "E:\\aa.txt",
      "E:\\bb.txt",
      "E:\\cc.txt"
    )

    for (f <- files) {
      //1.创建
      val task = new Task
      //2.启动
      task.start()
      //3.发送
      val reply: Future[Any] = task !! SubmitTask(f)
      //4.把每一个future加入到Set集合中
      futureSet += reply
    }

    //遍历
    while (futureSet.size > 0) {  //此时size为3
      //过滤出有真正结果数据的future
      val set: mutable.HashSet[Future[Any]] = futureSet.filter(x => x.isSet) //拿到已经有数据的future

      //遍历集合,获取到每一个有真正数据的future
      for (c <- set) {
        val value: Any = c.apply()
        resultList += value.asInstanceOf[ResultTask]
        //从futureSet移除掉 取出的future
        futureSet -= c
      }
    }
    //println(resultList.map(x=>x.result).flatten)
    println(resultList.flatMap(x => x.result).groupBy(x => x._1))
    //运行结果:Map(dog -> ListBuffer((dog,1)), cat -> ListBuffer((cat,1)), small -> ListBuffer((small,1)), hello -> ListBuffer((hello,1)))
    println(resultList.flatMap(x => x.result).groupBy(x => x._1)
            .mapValues(x => x.foldLeft(0)((x, y) => x + y._2)))
    //运行结果:Map(dog -> 1, cat -> 1, small -> 1, hello -> 1)

  }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值