Skip to content

Commit 6491042

Browse files
committed
optimize inner linked in actor-system & terminology
1 parent 7e03d68 commit 6491042

File tree

3 files changed

+30
-22
lines changed

3 files changed

+30
-22
lines changed

.gitignore

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1-
target
2-
.iml
1+
/target/
2+
3+
### IntelliJ IDEA ###
4+
.idea
5+
*.iws
6+
*.iml
7+
*.ipr
8+
*.jar
9+
*.class
10+
311
.DS_Store

articles/general-concepts/actor-systems.md

+10-10
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Actor 是封装状态和行为的对象,它们通过交换放在收件人邮
44
- **注释**`ActorSystem`是一个重量级架构,它将分配`1 … N`个线程,因此为每个逻辑应用程序都创建一个线程。
55

66
## 层次结构
7-
就像在经济组织中一样,Actor 自然形成等级制度。一个负责监督程序中某个函数的 Actor 可能希望将其任务拆分为更小、更易于管理的部分。为此,它启动了由它监督的子 Actor。在「[这里](https://doc.akka.io/docs/akka/current/general/supervision.html)」解释监督细节的同时,我们将集中讨论本节中的基本概念。唯一的先决条件是要知道每个 Actor 只有一个监督者,这就是创建它的 Actor。
7+
就像在经济组织中一样,Actor 自然形成等级制度。一个负责监督程序中某个函数的 Actor 可能希望将其任务拆分为更小、更易于管理的部分。为此,它启动了由它监督的子 Actor。在「[这里](https://github.com/guobinhit/akka-guide/blob/master/articles/general-concepts/supervision.md)」解释监督细节的同时,我们将集中讨论本节中的基本概念。唯一的先决条件是要知道每个 Actor 只有一个监督者,这就是创建它的 Actor。
88

99
Actor 系统的典型特征是,任务被拆分和委托,直到它们变得足够小,可以一块处理。这样做,不仅任务本身结构清晰,而且结果 Actor 可以根据他们应该处理哪些消息、应该如何正常反应以及应该如何处理失败来进行推理。如果一个 Actor 没有处理特定情况的方法,它会向其监督 Actor 发送相应的失败消息,请求帮助。然后,递归结构允许在正确的级别处理故障。
1010

@@ -13,30 +13,30 @@ Actor 系统的典型特征是,任务被拆分和委托,直到它们变得
1313
现在,设计这样一个系统的困难在于如何决定谁应该监督什么。没有单一的最佳解决方案,但有一些指导方针可能会有所帮助:
1414

1515
- 如果一个 Actor 管理另一个 Actor 正在做的工作,例如通过传递子任务,那么管理 Actor 应该监督子 Actor。原因是管理 Actor 知道预期的故障类型以及如何处理。
16-
- 如果一个 Actor 携带非常重要的数据(即,如果可以避免,其状态不会丢失),则该 Actor 应向其监督的子 Actor 找出任何可能危险的子任务,并处理这些子 Actor 的故障。根据请求的性质,最好为每个请求创建一个新的子级,这样可以简化收集答复的状态管理。这就是 Erlang 的“错误内核模式`Error Kernel Pattern`”。
17-
- 如果一个 Actor 依靠另一个 Actor 来履行职责,它应该观察另一个 Actor 的活动`liveness`,并在接到终止通知后采取行动。这与监督不同,因为监督方对监督策略没有影响,应该注意的是,单独的功能依赖性并不是决定将某个子 Actor 放在层级中何处的标准。
16+
- 如果一个 Actor 携带非常重要的数据(即,如果可以避免,其状态不会丢失),则该 Actor 应向其监督的子 Actor 找出任何可能危险的子任务,并处理这些子 Actor 的故障。根据请求的性质,最好为每个请求创建一个新的子级,这样可以简化收集答复的状态管理。这就是 Erlang 的“错误内核模式”。
17+
- 如果一个 Actor 依靠另一个 Actor 来履行职责,它应该观察另一个 Actor 的活动,并在接到终止通知后采取行动。这与监督不同,因为监督方对监督策略没有影响,应该注意的是,单独的功能依赖性并不是决定将某个子 Actor 放在层级中何处的标准。
1818

1919
这些规则总是有例外的,但是不管你是遵守规则还是违反规则,你都应该有一个理由。
2020

2121
## 配置容器
2222

23-
Actor 系统作为 Actor 的协作集合,是管理共享设施(如调度服务、配置、日志记录等)的自然单元。具有不同配置的多个 Actor 系统可以在同一个 JVM 中共存,没有问题,Akka 本身没有全局共享状态。将其与一个节点内或通过网络连接的 Actor 系统之间的透明通信结合起来,可以看到 Actor 系统本身可以用作功能层次结构中的构建块`building blocks`
23+
Actor 系统作为 Actor 的协作集合,是管理共享设施(如调度服务、配置、日志记录等)的自然单元。具有不同配置的多个 Actor 系统可以在同一个 JVM 中共存,没有问题,Akka 本身没有全局共享状态。将其与一个节点内或通过网络连接的 Actor 系统之间的透明通信结合起来,可以看到 Actor 系统本身可以用作功能层次结构中的构建块。
2424

2525
## Actor 最佳实践
2626

27-
1. Actor 应该像好的同事一样:高效地工作,而不是不必要地打扰其他人,并且避免占用资源。翻译成编程,这意味着以事件驱动的方式处理事件并生成响应(或更多请求)。Actor 不应在可能是锁、网络套接字等的外部实体上阻塞(即占用线程时被动等待,除非这是不可避免的;对于后一种情况,请参见下文。
28-
2. 不要在 Actor 之间传递可变对象。为了确保这一点,最好选择不可变的消息。如果通过将它们的可变状态暴露到外部来破坏 Actor 的封装,则返回正常的 Java 并发域`concurrency land`,并存在所有的缺点。
27+
1. Actor 应该像好的同事一样:高效地工作,而不是不必要地打扰其他人,并且避免占用资源。翻译成编程语言,这意味着以事件驱动的方式处理事件并生成响应(或更多请求)。Actor 不应在可能是锁、网络套接字等外部实体上阻塞,即占用线程时被动等待,除非这是不可避免的;对于后一种情况,请参见下文。
28+
2. 不要在 Actor 之间传递可变对象。为了确保这一点,最好选择不可变的消息。如果通过将它们的可变状态暴露到外部来破坏 Actor 的封装,则会返回正常的 Java 并发域,并存在所有的缺点。
2929
3. Actor 被设计成行为和状态的容器,接受这一点意味着不经常在消息中发送行为(使用 Scala 闭包可能很诱人)。其中一个风险是不小心在 Actor 之间共享可变状态,而这种对 Actor 模型的违反不幸地破坏了所有属性。
30-
4. 顶级 Actor 是错误内核(`Error Kernel`)的最核心部分,因此要谨慎地创建它们,并且更倾向于真正的分层系统。这对于故障处理(同时考虑配置的粒度和性能)有好处,而且它还减少了对守护者`guardian` Actor 的压力,如果使用过度,这是一个单一的竞争点。
30+
4. 顶级 Actor 是错误内核的最核心部分,因此要谨慎地创建它们,并且更倾向于真正的分层系统。这对于故障处理(同时考虑配置的粒度和性能)有好处,而且它还减少了对守护者 Actor 的压力,如果使用过度,这是一个单一的竞争点。
3131

3232
## 你不应该关心的事
33-
Actor 系统管理配置为使用的资源,以便运行其包含的 Actor。在一个这样的系统中,可能有数百万的 Actor,毕竟所有的赞歌(`mantra`)都是将他们视为丰富的,并且他们在每个实例的开销只有大约 300 字节。当然,在大型系统中处理消息的确切顺序不受应用程序作者的控制,但这也是无意的。
33+
Actor 系统管理配置使用的资源,以便运行其包含的 Actor。在一个这样的系统中,可能有数百万的 Actor,毕竟所有的赞歌(`mantra`)都是将他们视为丰富的,并且他们在每个实例的开销只有大约 300 字节。当然,在大型系统中处理消息的确切顺序不受应用程序作者的控制,但这也是无意的。
3434

3535
## 终止 ActorSystem
3636

37-
当你知道应用程序的所有操作都已完成时,可以调`ActorSystem``terminate`方法。这将停止守护者 Actor,而守护者 Actor 又将递归地停止其所有子 Actor,即系统守护者`system guardian`
37+
当你知道应用程序的所有操作都已完成时,可以调`ActorSystem``terminate`方法。这将停止守护者 Actor,而守护者 Actor 又将递归地停止其所有子 Actor,即系统守护者。
3838

39-
如果要在终止`ActorSystem`时执行某些操作,请查看「[CoordinatedShutdown](https://doc.akka.io/docs/akka/current/actors.html#coordinated-shutdown)」。
39+
如果要在终止`ActorSystem`时执行某些操作,请查看「[协调关闭](https://github.com/guobinhit/akka-guide/blob/master/articles/actors/actors.md#%E5%8D%8F%E8%B0%83%E5%85%B3%E9%97%AD)」。
4040

4141
----------
4242

articles/general-concepts/terminology.md

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# 术语及概念
2-
在本章中,我们试图建立一个通用的术语来定义一个坚实的基础,用于交流 Akka 所针对的并发和分布式系统。请注意,对于这些术语中的许多,并没有一个统一的定义。我们试图给出将在 Akka 文档范围内使用的定义。
2+
在本章中,我们试图建立一个通用的术语来定义一个坚实的基础,用于交流 Akka 所针对的并发和分布式系统。请注意,对于这其中的许多术语,并没有一个统一的定义。我们试图给出将在 Akka 文档范围内使用的定义。
33

44
## 并发 vs. 并行
55
并发和并行是相关的概念,但有一些小的区别。并发意味着两个或多个任务正在取得进展,即使它们可能不会同时执行。例如,这可以通过时间切片来实现,其中部分任务按顺序执行,并与其他任务的部分混合。另一方面,当执行的任务可以真正同时进行时,就会出现并行。
@@ -10,12 +10,12 @@
1010
同步 API 可以使用阻塞来实现同步,但这不是必要的。CPU 密集型任务可能会产生类似于阻塞的行为。一般来说,最好使用异步 API,因为它们保证系统能够进行。Actor 本质上是异步的:Actor 可以在消息发送之后进行其他任务,而不必等待实际的传递发生。
1111

1212
## 非阻塞 vs. 阻塞
13-
如果一个线程的延迟可以无限期地延迟其他一些线程,我们将讨论阻塞。一个很好的例子是,一个线程可以使用互斥来独占使用一个资源。如果一个线程无限期地占用资源(例如意外运行无限循环),则等待该资源的其他线程将无法进行。相反,非阻塞意味着没有线程能够无限期地延迟其他线程。
13+
如果一个线程的延迟可以无限期地延迟其他一些线程,这就是我们讨论的阻塞。一个很好的例子是,一个线程可以使用互斥来独占使用一个资源。如果一个线程无限期地占用资源(例如意外运行无限循环),则等待该资源的其他线程将无法进行。相反,非阻塞意味着没有线程能够无限期地延迟其他线程。
1414

1515
非阻塞操作优先于阻塞操作,因为当系统包含阻塞操作时,系统的总体进度并不能得到很好的保证。
1616

1717
## 死锁 vs. 饥饿 vs. 活锁
18-
当几个 Actor 在等待对方达到某个特定的状态以便能够取得进展时,就会出现死锁(`Deadlock`)。由于没有其他 Actor 达到某种状态(一个`Catch-22`问题),所有受影响的子系统都无法继续运行。死锁与阻塞密切相关,因为 Actor 线程能够无限期地延迟其他线程的进程。
18+
当多个 Actor 在等待对方达到某个特定的状态以便能够取得进展时,就会出现死锁(`Deadlock`)。由于没有其他 Actor 达到某种状态(一个`Catch-22`问题),所有受影响的子系统都无法继续运行。死锁与阻塞密切相关,因为 Actor 线程能够无限期地延迟其他线程的进程。
1919

2020
在死锁的情况下,没有 Actor 可以取得进展,相反,当有 Actor 可以取得进展,但可能有一个或多个 Actor 不能取得进展时,就会发生饥饿(`Starvation`)。典型的场景是一个调度算法,它总是选择高优先级的任务而不是低优先级的任务。如果传入的高优先级任务的数量一直足够多,那么低优先级任务将永远不会完成。
2121

@@ -24,21 +24,21 @@
2424
## 竟态条件
2525
当一组事件的顺序的假设可能被外部的非确定性(`non-deterministic`)因素影响时,我们称之为竟态条件(`Race condition`)。当多个线程具有共享可变状态时,常常会出现竟态条件,并且线程在该状态上的操作可能会交错进行,从而导致意外的行为。虽然这是一个常见的情况,但是共享状态不需要有竟态条件。例如,客户机向服务器发送无序数据包(如 UDP 数据报)`P1``P2`。由于数据包可能通过不同的网络路由传输,因此服务器可能先接收到`P2`,然后接收到`P1`。如果消息不包含有关其发送顺序的信息,则服务器无法确定它们是以不同的顺序发送的。根据包(`packets`)的含义,这可能导致竟态条件。
2626

27-
- **注释**:Akka 提供的关于在给定的两个 Actor 之间发送的消息的唯一保证是,他们的顺序始终保持不变。详见「[Message Delivery Reliability](https://doc.akka.io/docs/akka/current/general/message-delivery-reliability.html)」。
27+
- **注释**:Akka 提供的关于在给定的两个 Actor 之间发送的消息的唯一保证是,他们的顺序始终保持不变。详见「[消息传递可靠性](https://github.com/guobinhit/akka-guide/blob/master/articles/general-concepts/message-delivery-reliability.md)」。
2828

2929
## 非阻塞保证(进度条件)
3030
如前几节所讨论的,阻塞是不可取的,原因有几个,包括死锁的危险和系统中吞吐量的降低。在下面的章节中,我们将讨论具有不同强度的各种非阻塞特性。
3131

32-
### 等待自由(Wait-freedom)
33-
如果保证每个调用都以有限的步骤完成,则方法是无等待`wait-free`)的。如果一个方法是有界“无等待”的,那么步骤的数量有一个有限的上限。
32+
### 等待自由
33+
如果保证每个调用都以有限的步骤完成,则方法是无等待的,即等待自由`wait-freedom`。如果一个方法是有界“无等待”的,那么步骤的数量有一个有限的上限。
3434

3535
根据这个定义,无等待方法永远不会被阻塞,因此不会发生死锁。此外,由于每个 Actor 都可以在有限的步骤之后(调用完成时)继续进行,因此无等待方法没有饥饿。
3636

37-
### 锁自由(Lock-freedom)
38-
锁自由比等待自由更弱。在无锁调用的情况下,某些方法以有限的步数完成可能导致无限的等待(`infinitely often some method finishes in a finite number of steps`。这个定义意味着没有死锁的调用是不可能的。另一方面,某些调用以有限的步骤完成的保证不足以保证所有调用最终都完成。换句话说,锁自由不足以保证不发生饥饿。
37+
### 锁自由
38+
锁自由(`lock-freedom`)比等待自由更弱。在无锁调用的情况下,某些方法以有限的步数完成可能导致无限的等待。这个定义意味着没有死锁的调用是不可能的。另一方面,某些调用以有限的步骤完成的保证不足以保证所有调用最终都完成。换句话说,锁自由不足以保证不发生饥饿。
3939

40-
### 障碍自由(Obstruction-freedom)
41-
障碍自由是本文讨论的最薄弱的非阻塞保证。如果一个方法在某个时间点之后独立执行(其他线程不执行任何步骤,例如:挂起),则该方法称为无障碍的,它以有限的步骤完成。所有无锁(`lock-free`)对象都是无障碍(`obstruction-free`)的,但相反的情况通常是不正确的。
40+
### 障碍自由
41+
障碍自由(`obstruction-freedom`)是本文讨论的最薄弱的非阻塞保证。如果一个方法在某个时间点之后独立执行(其他线程不执行任何步骤,例如:挂起),则该方法称为无障碍的,它以有限的步骤完成。所有锁自由对象都是无障碍的,但相反的情况通常是不正确的。
4242

4343
乐观并发控制(OCC)方法通常是无障碍的。OCC 方法是,每个 Actor 都试图在共享对象上执行其操作,但如果 Actor 检测到来自其他对象的冲突,则会回滚修改,并根据某些计划重试。如果有一个时间点,其中一个 Actor 是唯一的尝试者,那么操作将成功。
4444

0 commit comments

Comments
 (0)