系统扩展:并行工作、路由与调度器的高效运用
立即解锁
发布时间: 2025-08-25 02:35:29 阅读量: 2 订阅数: 8 

# 系统扩展:并行工作、路由与调度器的高效运用
## 1. 使用 Actor 并行工作
此前我们探讨过使用 Future 实现并行工作,现在来看看如何利用 Actor 达成类似的并行效果。需注意,在示例中使用 Future 时代码十分简洁,但依据具体用例,专门为并发使用 Actor 可能会使代码更复杂。接下来我们通过一个使用 Actor 完成工作的等效示例进行说明。
### 1.1 创建 Actor
借助 Future 示例中的 `ArticleParser` 静态应用方法,我们先创建一个执行工作的 Actor。以下是 Java 和 Scala 代码示例:
#### Java 代码
```java
public class ParseArticle {
public final String htmlBody;
public ParseArticle(String url) {
this.htmlBody = url;
}
}
public class ArticleParseActor extends AbstractActor {
private ArticleParseActor() {
receive(ReceiveBuilder.
match(ParseArticle.class, x ->{
sender().tell(ArticleParser.apply(x.htmlBody), self());
}
).
build());
}
}
```
#### Scala 代码
```scala
case class ParseArticle(htmlString: String)
class ArticleParseActor extends Actor{
override def receive: Receive = {
case ParseArticle(htmlString) =>
val body: String = ArticleParser(htmlString)
sender() ! body
}
}
```
若要并行执行工作,我们需引入“Router”将工作分配给多个 Actor,下面将详细介绍。
## 2. 引入 Router
在 Akka 中,Router 是一种负载均衡和路由抽象。创建 Router 时,可为其提供一组 Actor 或者让它创建一个 Actor 池。
### 2.1 Actor 集合的创建方式
创建带有 Actor 的 Router 时,要明白 Router 背后的 Actor 集合有两种创建方式:Router 可以创建 Actor(Pool),也可以被提供一个 Actor 列表(Group)。
### 2.2 Router 的工作原理
Router 创建完成后,若接收到消息,它会将消息传递给其 Group 或 Pool 中的一个或多个 Actor。有多种策略可决定 Router 选择下一个消息转发的 Actor 的顺序。
### 2.3 创建 Router
对于本地 Actor 的用例,我们可以将 Router 创建为一个 Pool,让 Router 为我们创建所有的 Actor。在这种情况下使用 Router 很简单,我们像往常一样实例化一个 Actor,然后调用 `withRouter` 方法,传入路由策略和所需的 Actor 数量。Scala 和 Java 的实现方式相同:
#### Java 代码
```java
ActorRef workerRouter =
system.actorOf(
Props.create(ArticleParseActor.class).
withRouter(new RoundRobinPool(8)));
```
#### Scala 代码
```scala
val workerRouter: ActorRef =
system.actorOf(
Props.create(classOf[ArticleParseActor]).
withRouter(new RoundRobinPool(8)))
```
若有一个 Actor 列表并想从中创建一个 Router,我们可以从 Group 创建 Router,提供 Actor 的路径列表:
#### Java 代码
```java
ActorRef router = system.actorOf(new RoundRobinGroup(actors.map(actor -> actor.path()).props());
```
#### Scala 代码
```scala
val router = system.actorOf(new RoundRobinGroup(actors.map(actor => actor.path).props())
```
此时,我们拥有了所需的 Router 和 Actor,能够在多个核心间分配负载。将消息列表交给 Router 处理,它会并行处理这些消息。接下来,我们深入了解 Router 的高级特性,以便更详细地掌握其工作原理。
### 2.4 路由逻辑
我们使用了 `RoundRobinPool` 或 `RoundRobinGroup`,它们决定了消息传递给 Router 的顺序。Akka 自带了多种路由策略,下面介绍几种常见的策略:
| 路由策略 | 功能描述 |
| --- | --- |
| Round Robin | 按顺序将消息发送到 Pool 或 Group 中的每个节点,然后重新开始。 |
| Random | 随机发送消息。 |
| Smallest Mailbox | 将消息发送到消息最少的 Actor。由于远程 Actor 的邮箱大小未知,假定它们有消息排队,因此会优先处理空闲的本地 Actor。 |
| Scatter Gather | 将消息发送到 Group 或 Pool 中的所有 Actor,并使用接收到的第一个响应,丢弃其他响应。若需要确保获得响应且希望尽快得到,可使用此策略。 |
| Tail Chopping | 与 Scatter Gather 类似,但不是一次性将消息发送到组/池中的所有 Actor,而是为每个后续消息等待一小段时间。与 Scatter Gather 有类似的优点,但可能会减少负载。 |
| Consistent Hashing | 为 Router 提供一个键,然后对其进行哈希处理。哈希后的键用于确定将数据发送到哪个节点。在将特定“数据切片”分配到特定目的地时使用,常用于服务器集群。 |
| BalancingPool | 这是一种独特的 Router,只能用于本地 Actor。Actor 共享一个邮箱,并以工作窃取的方式从中获取工作,有助于确保所有 Actor 都保持忙碌。对于本地集群,这通常是首选的路由机制。 |
你也可以自定义路由逻辑,但通常无需这样做。
### 2.5 向 Router 中的所有 Actor 发送消息
0
0
复制全文
相关推荐










