并发编程模型Akka

  1. 并发编程模型 Akka

 

    1. Akka 介绍

 

写并发程序很难。程序员不得不处理线程、锁和竞态条件等等,这个过程很容易出错,而且   会导致程序代码难以阅读、测试和维护。

 

Akka 是 JVM 平台上构建高并发、分布式和容错应用的工具包和运行时。Akka 用 Scala 语言写成,同时提供了 Scala 和 JAVA 的开发接口。

 

 

    1. Akka Actor 模型

 

Akka 处理并发的方法基于 Actor 模型。在基于 Actor 的系统里,所有的事物都是 Actor,就好像在面向对象设计里面所有的事物都是对象一样。但是有一个重要区别,那就是 Actor 模型是作为一个并发模型设计和架构的,而面向对象模式则不是。Actor 与 Actor 之间只能通过消息通信。

 

  1. 对并发模型进行了更高的抽象
  2. 异步、非阻塞、高性能的事件驱动编程模型
  3. 轻量级事件处理(1GB 内存可容纳百万级别个 Actor)

 

为什么 Actor 模型是一种处理并发问题的解决方案?

处理并发问题就是如何保证共享数据的一致性和正确性,为什么会有保持共享数据正确   性这个问题呢?无非是我们的程序是多线程的,多个线程对同一个数据进行修改,若不加同   步条件,势必会造成数据污染。那么我们是不是可以转换一下思维,用单线程去处理相应的   请求,但是又有人会问了,若是用单线程处理,那系统的性能又如何保证。Actor 模型的出现解决了这个问题,简化并发编程,提升程序性能。

 

并发编程模型Akka_第1张图片

 

从图中可以看到,Actor 与 Actor 之前只能用消息进行通信,当某一个 Actor 给另外一个 Actor 发消息,消息是有顺序的,只需要将消息投寄的相应的邮箱,至于对方 Actor 怎么处理你的消息你并不知道,当然你也可等待它的回复。

 

Actor 是 ActorSystem 创建的, ActorSystem 的职责是负责创建并管理其创建的 Actor, ActorSystem 的单例的,一个 JVM 进程中有一个即可,而 Acotr 是多例的。

Pom 依赖:

 


    UTF-8

    2.11.8

    2.11

    2.4.17





    

    

        org.scala-lang

        scala-library

        ${scala.version}

    

    

    

        com.typesafe.akka

        akka-actor_${scala.compat.version}

        ${akka.version}

    

    

    

        com.typesafe.akka

        akka-remote_${scala.compat.version}

        ${akka.version}

    







    

    src/main/scala

    src/test/scala

    

        

        

            net.alchim31.maven

            scala-maven-plugin

            3.2.2

            

                

                    

                        compile

                        testCompile

                    

                    

                        

                            -dependencyfile

                            ${project.build.directory}/.scala_dependencies

                        

                    

                

            

        

        

        

            org.apache.maven.plugins

            maven-shade-plugin

            2.4.3

            

                

                    package

                    



                        shade

                    

                    

                        

                            

                                *:*

                                

                                    META-INF/*.SF

                                    META-INF/*.DSA

                                    META-INF/*.RSA

                                

                            

                        

                        

                            

                                reference.conf

                            

                            

                            

                                

                            

                        

                    

                

            

        

    

 

 

 

 

 

 

    1. 案例--HelloActor
package com.zpark.actor

import akka.actor.{Actor, ActorRef, ActorSystem, Props}
//线程池,会一直运行,怎么停止?context.stop(self)
class HelloActor extends Actor {
  //接收消息
  override def receive: Receive = {
    //偏函数怎么用?case:
    case "hello" => println("hi")
    case "hey" => println("oooops")
    case "stop" => {
      context.stop(self)
      context.system.terminate()  //关闭ActorySystem
    }
  }
}

object HelloActor {
  //里面有apply方法
  private val lucasFactory = ActorSystem("lucasFactory")//工厂
  //helloActorRef:用来发送消息的
  private val helloActorRef: ActorRef = lucasFactory.actorOf(Props[HelloActor])

  def main(args: Array[String]): Unit = {
    helloActorRef ! "hello"  //! 的作用是  发送
    helloActorRef ! "hey"

    helloActorRef ! "stop"
  }
}
    1. 案例--PingPong

LucasActor

package com.zpark.actor

import akka.actor.{Actor, ActorRef}

class LucasActor(val jk: ActorRef) extends Actor{
  override def receive: Receive = {
    case "start" => {
      println("lucas:i'm ready")
      jk ! "pa"
    }
    case "papa" => {
      println("ok")
      Thread.sleep(1000)
      jk ! "pa"
    }
  }
}

JackActory

package com.zpark.actor

import akka.actor.Actor

class JackActor extends Actor{
  override def receive: Receive = {
    case "start" => println("jack:i'm ready")
    case "pa" => {
      println("jack: go")
      Thread.sleep(1000)
      sender() ! "papa" //发给case "pa"的发送者
    }
  }
}

Main

package com.zpark.actor

import akka.actor.{ActorSystem, Props}

object PingpangApp {
  def main(args: Array[String]): Unit = {
    //通过ActorSystem创建ActorRef
    val pingPangActorSystem = ActorSystem("PingPangActorSystem")
    val jfActorRef = pingPangActorSystem.actorOf(Props[JackActor], "jf")
    val lfActorRef = pingPangActorSystem.actorOf(Props(new LucasActor(jfActorRef)), "lf")

    lfActorRef ! "start"
    jfActorRef ! "start"
  }
}
    1. 案例基于 Actor 的聊天模型

 

 并发编程模型Akka_第2张图片

 

package com.zpark.robot

import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import com.typesafe.config.ConfigFactory

/**
  * 服务端
  */
class ZparkServer extends Actor{
  override def receive: Receive = {
    case "start" => println("就绪....")
    case ClientMessage(msg) => {
      println(s"收到客户端消息$msg")
      msg match {
        case "你叫啥" => sender() ! ServerMessage("我叫机器人")
        case "你是男是女" => sender() ! ServerMessage("男")
        case "你有男票吗" => sender() ! ServerMessage("没有")
        case _ => sender() ! ServerMessage("不知道")
      }
    }


  }
}

/**
  * 服务端启动入口
  */
object ZparkServer extends App {
  val host: String = "127.0.0.1"
  val port: Int = 8878
  val conf = ConfigFactory.parseString(
    s"""
      |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
      |akka.remote.netty.tcp.hostname = $host
      |akka.remote.netty.tcp.port = $port
    """.stripMargin
  )
  //启动的时候指定ip地址和端口
  private val actorSystem = ActorSystem("Server",conf)
  private val serverActorRef: ActorRef = actorSystem.actorOf(Props[ZparkServer],"xiaohua")
  serverActorRef ! "start"

}

 

 

package com.zpark.robot

import akka.actor.{Actor, ActorRef, ActorSelection, ActorSystem, Props}
import com.typesafe.config.ConfigFactory

import scala.io.StdIn

/**
  * 客户端
  */
class ClientActor extends Actor{
  var serverActorRef: ActorSelection = _
  override def preStart(): Unit = {
    serverActorRef = context.actorSelection("akka.tcp://[email protected]:8878/user/xiaohua")
  }
  override def receive: Receive = {
    case "start" => "client01 已启动"
    case msg: String => {
      serverActorRef ! ClientMessage(msg)
    }
    case ServerMessage(msg) => println(s"收到服务端消$msg")
  }
}

/**
  * 客户端启动入口
  */
object ClientActor extends App {
  val host: String = "127.0.0.1"
  val port = 8880
  val conf = ConfigFactory.parseString(
    s"""
       |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
       |akka.remote.netty.tcp.hostname = $host
       |akka.remote.netty.tcp.port = $port
    """.stripMargin
  )
  private val clientSystem = ActorSystem("client",conf)
  private val client01ActorRef: ActorRef = clientSystem.actorOf(Props[ClientActor],"client02")
  client01ActorRef ! "start"

  while (true) {
    val question = StdIn.readLine()
    client01ActorRef ! question
  }
}
package com.zpark.robot

//服务端发送给客户段的消息
case class ServerMessage(msg: String)
//客户端发送给服务器端的消息格式
case class ClientMessage(msg: String)

 

参数:

akka.actor.provider = "akka.remote.RemoteActorRefProvider"

akka.remote.netty.tcp.hostname = $host

akka.remote.netty.tcp.port = $port

      1. 创建一个 Server 端用于服务客户端发送过来的问题,并作处理并返回信息给客户

端!

      1. 创建一个 Client 端,用于向服务端发送问题,并接收服务端发送过来的消息!

 

    1. 案例 Spark Master Worker 进程通信示例

你可能感兴趣的:(并发编程模型Akka)