并发编程模型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 模型的出现解决了这个问题,简化并发编程,提升程序性能。

 

 

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

 

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

Pom 依赖:

 
<properties>

    <encoding>UTF-8</encoding>

    <scala.version>2.11.8</scala.version>

    <scala.compat.version>2.11</scala.compat.version>

    <akka.version>2.4.17</akka.version>

</properties>

<dependencies>

    <!-- 添加 scala 的依赖 -->

    <dependency>

        <groupId>org.scala-lang</groupId>

        <artifactId>scala-library</artifactId>

        <version>${scala.version}</version>

    </dependency>

    <!-- 添加 akka 的 actor 依赖  typesafe读取配置文件-->

    <dependency>

        <groupId>com.typesafe.akka</groupId>

        <artifactId>akka-actor_${scala.compat.version}</artifactId>

        <version>${akka.version}</version>

    </dependency>

    <!-- 多进程之间的 Actor 通信 -->

    <dependency>

        <groupId>com.typesafe.akka</groupId>

        <artifactId>akka-remote_${scala.compat.version}</artifactId>

        <version>${akka.version}</version>

    </dependency>

</dependencies>

<!-- 指定插件-->

<build>

    <!-- 指定源码包和测试包的位置 -->

    <sourceDirectory>src/main/scala</sourceDirectory>

    <testSourceDirectory>src/test/scala</testSourceDirectory>

    <plugins>

        <!-- 指定编译 scala 的插件 -->

        <plugin>

            <groupId>net.alchim31.maven</groupId>

            <artifactId>scala-maven-plugin</artifactId>

            <version>3.2.2</version>

            <executions>

                <execution>

                    <goals>

                        <goal>compile</goal>

                        <goal>testCompile</goal>

                    </goals>

                    <configuration>

                        <args>

                            <arg>-dependencyfile</arg>

                            <arg>${project.build.directory}/.scala_dependencies</arg>

                        </args>

                    </configuration>

                </execution>

            </executions>

        </plugin>

        <!-- maven 打包的插件 -->

        <plugin>

            <groupId>org.apache.maven.plugins</groupId>

            <artifactId>maven-shade-plugin</artifactId>

            <version>2.4.3</version>

            <executions>

                <execution>

                    <phase>package</phase>

                    <goals>



                        <goal>shade</goal>

                    </goals>

                    <configuration>

                        <filters>

                            <filter>

                                <artifact>*:*</artifact>

                                <excludes>

                                    <exclude>META-INF/*.SF</exclude>

                                    <exclude>META-INF/*.DSA</exclude>

                                    <exclude>META-INF/*.RSA</exclude>

                                </excludes>

                            </filter>

                        </filters>

                        <transformers>

                            <transformer

                                    implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">

                                <resource>reference.conf</resource>

                            </transformer>

                            <!-- 指定 main 方法 -->

                            <transformer

                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">

                                <mainClass></mainClass>

                            </transformer>

                        </transformers>

                    </configuration>

                </execution>

            </executions>

        </plugin>

    </plugins>

</build>
 

 

 

 

 

 

    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 的聊天模型

 

 

 

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://Server@127.0.0.1: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 进程通信示例
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值