并发编程模型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 进程通信示例
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值