博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
actor akka_如果您仍在使用同步,则应改用Akka Actor-这就是为什么
阅读量:2530 次
发布时间:2019-05-11

本文共 7156 字,大约阅读时间需要 23 分钟。

actor akka

by Martin Budi

马丁·布迪(Martin Budi)

如果您仍在使用同步,则应改用Akka Actor-这就是为什么 (If you’re still using Synchronized, you should try Akka Actor instead — here’s why)

Synchronized is Java’s traditional concurrency mechanism. Although it is probably not something we see often these days, it is still fueling many libraries. The problem is, synchronized is both blocking and complicated. In this article, I’d like to illustrate the issue in a simple way and my reasoning to move to Akka Actor for better and easier concurrency.

同步是Java的传统并发机制。 尽管这些天我们可能很少见到它,但它仍在推动着许多图书馆的发展。 问题是,同步既阻塞又复杂。 在本文中,我想以一种简单的方式来说明这个问题,并说明我选择Akka Actor获得更好和更轻松的并发性的理由。

Consider this simple code:

考虑以下简单代码:

int x;   if (x > 0) {   return true; } else {   return false; }

So return true if x is positive. Simple.

因此,如果x为正,则返回true。 简单。

Next, consider this even simpler code:

接下来,考虑以下更简单的代码:

x++;

Yes, a counter. Very simple right?

是的,柜台。 很简单吧?

However, all these codes can blow up spectacularly in a multi-threaded environment.

但是,所有这些代码都可能在多线程环境中爆炸。

In the first example, true or false isn’t determined by the value of x. It is actually determined by the if-test. So, if another thread changes x to a negative right after the first thread passed the if-test, we’d still get true even if x is no longer positive.

在第一个示例中,true或false不是由x的值确定的。 它实际上由if-test确定。 因此,如果在第一个线程通过了if-test之后另一个线程将x更改为负数,即使x不再为正数,我们仍将为true。

The second example is pretty deceptive. Although it is just one line, there are actually three operations: reading x, incrementing it and putting the updated value back. If two threads run at exactly the same time, the update might be lost.

第二个例子具有欺骗性。 尽管只是一行,但实际上有三个操作:读取x ,将其递增和将更新后的值放回去。 如果两个线程恰好同时运行,则更新可能会丢失。

When we have different threads simultaneously accessing and modifying a variable, we have a race condition. If we just want to build a counter, Java provides thread-safe Atomic Variables, among them Atomic Integer which we can use for this purpose. Atomic Integer, however, only works on single variables. How do we make several operations atomic?

当我们有不同的线程同时访问和修改变量时,我们就有了竞争条件。 如果我们只想构建一个计数器,则Java提供了线程安全的Atomic变量,其中包括Atomic Integer,我们可以将其用于此目的。 但是,原子整数仅适用于单个变量。 我们如何使几个操作原子化?

By using synchronized block. First, let’s take a look at a more elaborate example.

通过使用同步块。 首先,让我们看一个更详细的例子。

int x; public int withdraw(int deduct){    int balance = x - deduct;     if (balance > 0) {      x = balance;      return deduct;    } else {      return 0;    }}

This is a very basic cash withdraw method. It also happens to be dangerous. Two threads running at the same time may cause the bank to issue two withdrawals even if the balance is no longer enough. Now let’s see how it works with synchronized block:

这是一种非常基本的现金提取方法。 这也很危险。 即使余额不足,两个线程同时运行也可能导致银行发出两次提款。 现在让我们看看它如何与同步块一起工作:

volatile int x;public int withdraw(int deduct){  synchronized(this){    int balance = x - deduct;     if (balance > 0) {      x = balance;      return deduct;    } else {      return 0;    }  }}

The idea of synchronized block is simple. One thread enters it and locks it, while other threads wait outside. The lock is an object, in our case this. After it’s done, the lock is released and passed to another thread which then does the same thing. Also, note the esoteric keyword volatile which is needed to prevent the thread from using the local CPU cache of x.

同步块的想法很简单。 一个线程进入并锁定它,而其他线程在外面等待。 锁是一个对象,在我们的例子中是this 。 完成后,将释放该锁并将其传递给另一个线程,然后该线程将执行相同的操作。 另外,请注意需要使用深奥的关键字volatile ,以防止线程使用x的本地CPU缓存

Now with the threads untangled, the bank won’t accidentally issue unfunded withdrawals. However, this structure tends to grow complex with more blocks and more locks. Dealing with multiple locks is particularly risky. The blocks might inadvertently hold the key for each other and end up locking the entire app. And on top of it, we have an efficiency issue. Remember that while a thread works inside, all the other threads wait outside. And waiting threads are well … waiting. They don’t do anything else but wait.

现在,随着线程的混乱,银行将不会意外地发行无资金的提款。 但是,这种结构往往随着更多的块和更多的锁而变得复杂。 处理多个锁特别危险。 这些块可能会在不经意间互相持有密钥并最终锁定整个应用程序。 最重要的是,我们存在效率问题。 记住,当一个线程在内部运行时,所有其他线程在外部等待。 等待线程很好……等待。 除了等待,他们别无选择。

So instead of doing such mechanism, why not just drop the job in a queue? To better visualize it, imagine an email system. When you send an email, you drop the email in the recipient’s mailbox. You don’t wait around until the person reads it.

因此,为什么不将工作放在队列中而不是采用这种机制呢? 为了更好地可视化它,请想象一个电子邮件系统。 发送电子邮件时,会将电子邮件拖放到收件人的邮箱中。 您无需等到该人读完它。

These are the basics of the Actor model and Akka framework in general.

这些通常是Actor模型和Akka框架的基础。

Actor encapsulates state and behavior. Unlike OOP’s encapsulation, though, actors do not expose their state and behavior at all. The only way for an actor to communicate with each other is by exchanging messages. Incoming messages are dropped in a mailbox and digested in first-in-first-out order. Here’s a reworked sample in Akka and Scala.

Actor封装状态和行为。 但是,与OOP的封装不同,actor根本不公开其状态和行为。 演员相互交流的唯一方法是交换消息。 传入邮件将被放入邮箱中,并按照先进先出的顺序进行摘要。 这是Akka和Scala中经过重做的示例。

case class Withdraw(deduct: Int)class ReplicaActor extends Actor {  var x = 10;  def receive: Receive = {    case Withdraw(deduct) => val r = withdraw(deduct)  }}class BossActor extends Actor {  var replica = context.actorOf(Props[ReplicaActor])  replica ! Withdraw(6)  replica ! Withdraw(9)   }

We have a ReplicaActor that does the work and BossActor that orders the replica around. First, notice the ! sign or tell. This is one of two methods (the other is ask) for an actor to asynchronously send a message to another actor. tell in particular does so without waiting for a reply. So the boss tells the replica to do two withdraw orders and immediately leaves. These messages arrive in the replica's receive where each one is popped and matched with the corresponding handler. In this case, Withdraw executes the withdraw method from the previous example and deducts the requested amount from state x. After it is done, the actor proceeds to the next message in the queue.

我们有一个ReplicaActor负责这项工作,而BossActor负责订购该副本。 首先,注意! 签名或告诉 。 这是一种Actor异步地将消息发送给另一个Actor的两种方法之一(另一个是ask )。 告诉尤其是在执行时不等待答复。 因此,老板告诉副本执行两次撤回命令并立即离开。 这些消息到达副本的接收器 ,其中每个消息都会弹出并与相应的处理程序匹配。 在这种情况下, 退出执行从前面的例子中的退出方法和扣除从状态X所请求的量。 完成后,参与者将前进到队列中的下一条消息。

So what do we get here? For one, we no longer need to worry about locking and working with atomic/concurrent types. Actor’s encapsulation and queuing mechanism already guarantee thread-safety. And there is no more waiting since threads just drop the message and return. Results can be delivered later with ask or tell. It’s simple and sane.

那我们到这里来做什么? 首先,我们不再需要担心锁定和使用原子/并发类型。 Actor的封装和排队机制已经保证了线程安全性。 由于线程只是丢弃消息并返回,因此不再等待。 结果可以稍后通过AskTell传递。 简单而理智。

Akka is based on JVM and available in both Scala and Java. Although this article isn’t debating Java vs Scala, Scala’s pattern matching and functional programming would be very useful in managing Actor’s data messaging. At the very least it can help you write shorter code by avoiding Java’s brackets and semicolons.

Akka基于JVM,并且在Scala和Java中均可用。 尽管本文并未讨论Java与Scala的争论,但Scala的模式匹配和函数式编程在管理Actor的数据消息传递方面将非常有用。 至少它可以避免Java的方括号和分号,从而帮助您编写较短的代码。

翻译自:

actor akka

转载地址:http://sjewd.baihongyu.com/

你可能感兴趣的文章
Spring CommonsMultipartResolver 上传文件
查看>>
Settings app简单学习记录
查看>>
SQLAlchemy
查看>>
多线程
查看>>
使用缓存的9大误区(下)转载
查看>>
appium键值对的应用
查看>>
MyEclipse 8.X 通用算法
查看>>
selenium.Phantomjs设置浏览器请求头
查看>>
分布式数据库如何选择,几种分布式数据库优缺点一览
查看>>
BZOJ 4443: 小凸玩矩阵【二分图】
查看>>
苹果 OS X制作u盘启动盘
查看>>
Jquery便利对象
查看>>
MVC: Connection String
查看>>
idea常用设置汇总
查看>>
Node.SelectNodes
查看>>
Lambda表达式语法进一步巩固
查看>>
Vue基础安装(精华)
查看>>
Git 提交修改内容和查看被修改的内容
查看>>
PAT - 1008. 数组元素循环右移问题 (20)
查看>>
请求出现 Nginx 413 Request Entity Too Large错误的解决方法
查看>>