简单易懂的Actor通讯系统栗子

本文详细介绍了使用Akka框架实现服务器与节点之间的远程通信过程。通过定义消息协议和常量,创建资源管理器和节点管理器,实现了消息的发送与接收。资源管理器在收到节点的消息后,会回调发送响应,展示了Akka在分布式系统中高效通信的能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用

定义消息协议

object Messages {

  case class Hello(content: String)
  case class World(content: String)

}

定义常量

object Cons {

  val ResourceManagerName = "ResourceManagerName"
  val NodeManagerName = "NodeManagerName"
  val ResourceActor = "ResourceActor"
  val NodeActor = "NodeActor"

}

服务器

import akka.actor._
import com.typesafe.config.{Config, ConfigFactory}

class MyResourceManager() extends Actor {
  override def receive: Receive = {
    case Messages.Hello(content: String) => {

      sender() ! Messages.World("服务器回调")
    }
  }
}

object MyResourceManagerMain {
  def main(args: Array[String]): Unit = {
    val str: String =
      """
        |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
        |akka.actor.warn-about-java-serializer-usage = off
        |akka.remote.netty.tcp.hostname = localhost
        |akka.remote.netty.tcp.port = 20000
      """.stripMargin
    val conf: Config = ConfigFactory.parseString(str)
    val actorSystem = ActorSystem(Cons.ResourceManagerName, conf)
    actorSystem.actorOf(Props(new MyResourceManager()), Cons.ResourceActor)
  }
}

节点

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

class MyNodeManager(resourceHost: String = "localhost", resourcePort: Int = 20000) extends Actor {

  var resourceManager: ActorSelection = _

  override def preStart(): Unit = {
    resourceManager = context.actorSelection(s"akka.tcp://${Cons.ResourceManagerName}@$resourceHost:$resourcePort/user/${Cons.ResourceActor}")

    resourceManager ! Messages.Hello("haha")
  }

  override def receive: Receive = {
    case Messages.World(content: String) => {
      println(content)
    }
  }
}

object MyNodeManagerMain {
  def main(args: Array[String]): Unit = {
    val str: String =
      """
        |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
        |akka.actor.warn-about-java-serializer-usage = off
        |akka.remote.netty.tcp.hostname = localhost
        |akka.remote.netty.tcp.port = 20001
      """.stripMargin
    val conf: Config = ConfigFactory.parseString(str)
    val actorSystem = ActorSystem(Cons.NodeManagerName, conf)
    actorSystem.actorOf(Props(new MyNodeManager()), Cons.NodeActor)
  }
}
  1. 启动 MyResourceManager
  2. 启动 MyNodeManager
[INFO] [02/21/2019 01:13:02.734] [main] [akka.remote.Remoting] Starting remoting
[INFO] [02/21/2019 01:13:02.878] [main] [akka.remote.Remoting] Remoting started; listening on addresses :[akka.tcp://NodeManagerName@localhost:20001]
[INFO] [02/21/2019 01:13:02.879] [main] [akka.remote.Remoting] Remoting now listens on addresses: [akka.tcp://NodeManagerName@localhost:20001]
服务器回调
<think>好的,用户之前让我解释过C语言中的if语句,现在他们又要求解释“初始化”,并且希望简单易懂。我需要先确定“初始化”在编程中的常见含义,可能是指变量的初始化,或者是程序的初始化过程。 用户可能是编程新手,所以要用最基础的概念来解释。首先,变量初始化是指在声明变量时赋予初始值。比如int a = 0;这样避免使用未初始化的变量导致错误。 接下来,我需要考虑用户可能遇到的常见问题,比如忘记初始化导致不可预知的结果,或者初始化的不同方式(声明时初始化、后续赋值)。可能需要用生活中的例子来比喻,比如准备做饭前先准备好食材,这样开始做的时候就不会手忙脚乱。 还要注意不同编程语言中初始化的差异,但用户之前问的是C语言,所以应该以C为例。另外,可能需要提到静态初始化、动态初始化,或者结构体、数组的初始化方法,但保持简单易懂,可能先讲基础,再稍微扩展。 要避免使用专业术语过多,用日常例子辅助理解。比如,把变量比作盒子,初始化就是往盒子里放初始的东西,这样用的时候就不会是空的。同时,提醒初始化的重要性,比如防止程序崩溃或逻辑错误。 可能还需要对比未初始化的情况,展示例子,说明为什么必要。比如未初始化的变量可能有随机值,导致计算结果错误。此外,可以给出一个简单的代码示例,演示正确初始化和未初始化的不同结果。 最后,检查是否有常见的误区需要提醒,比如在循环中重复初始化可能的问题,或者全局变量默认初始化为0而局部变量不会等。这些细节虽然重要,但要根据用户的接受程度决定是否深入。 总结下来,结构应该是:定义初始化,比喻解释,为什么重要,如何正确初始化,常见错误及示例。保持口语化,避免复杂术语,用用户之前能理解的if语句的例子来类比,帮助建立联系。</think>### 通俗版解释:编程中的“初始化” 可以把 **初始化** 想象成 **“做事前的准备工作”**。就像你开始玩游戏前要设定角色属性,做饭前要准备好食材一样,初始化就是给变量或程序设定 **“起点状态”**。 --- #### 🌰 **举个栗子** 假设你要用微波炉热牛奶: 1. **初始化微波炉** ➜ 插电源、开门、放牛奶 2. **执行操作** ➜ 设定时间,按启动键 如果没插电(没初始化)直接按启动键 ➜ 微波炉完全没反应! --- ### 🔑 **核心要点** #### 1. **变量初始化:给变量“第一口奶”** - 声明变量时直接赋值,避免出现“喝空气”的尴尬 ```c int 奶茶价格 = 20; // ✅ 正确初始化(明确知道价格) int 未知饮料价格; // ❌ 未初始化(可能随机出现奇怪数值) ``` #### 2. **初始化的本质是“消除不确定性”** - 就像快递员送货前必须知道地址: ```c char 收货地址[100] = "北京市朝阳区"; // ✅ 明确地址 char 收货地址[100]; // ❌ 地址可能是乱码 ``` #### 3. **常见初始化方式** | **类型** | **示例** | **效果** | |----------------|-----------------------------|--------------------------| | 直接赋值 | `int 年龄 = 18;` | 最直观的初始化方式 | | 后续赋值 | `int 温度; 温度 = 25;` | 分两步完成 | | 批量初始化 | `int 星期[7] = {1,2,3,4,5,6,7};` | 数组常用 | --- ### ⚠️ **新手常见坑** #### 1. **以为电脑会“自动填零”** - 全局变量默认初始化为0,但 **局部变量不会**! ```c void 函数() { int 未初始化变量; // 值可能是随机的(比如-12536) printf("%d", 未初始化变量); // 可能输出乱码 } ``` #### 2. **过度初始化浪费资源** - 像烧水时反复开壶盖检查: ```c for (int i=0; i<100; i++) { int 重复初始化 = 10; // ❌ 每次循环都重新创建变量 // 应该提到循环外初始化 } ``` --- ### 🛠️ **实战小例子** ```c #include <stdio.h> int main() { // ✅ 正确初始化案例 int 奶茶库存 = 50; // 明确知道初始库存 float 温度 = 25.5f; // 设定初始温度 char 店铺名[] = "快乐奶茶店"; // 字符串初始化 // ❌ 危险操作(未初始化) int 当日销量; printf("今天卖出%d杯\n", 当日销量); // 输出随机值! return 0; } ``` **可能输出**: ``` 今天卖出-2147483648杯 // 完全不合理的数据! ``` --- ### 🌟 **一句话总结** 初始化就像 **“给程序世界定规矩”**:让所有变量在出生时就有明确的值,避免它们像没头苍蝇一样乱撞。记住:**“宁可多写一行初始化,不要多查三天BUG”**! 🚀 试试在你的代码中给所有变量加上初始化,看看错误会不会变少吧!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值