我刚刚开始学习Scala中的Akka Actors。我的理解是,Actor接收的消息在Actor的邮箱中排队,并且一次处理一个。通过一次处理一个消息,可以减轻并发问题(竞争条件,死锁)。
但是如果Actor创建了一个未来来完成与消息相关的工作会发生什么呢?由于将来是异步的,因此Actor可以开始处理接下来的几条消息,而与先前消息相关联的未来仍在运行。这不会产生竞争条件吗?如何在Actor的receive()方法中安全地使用future来执行长时间运行的任务?
答案 0 :(得分:22)
在演员中使用未来最安全的方法是只在未来使用pipeTo
并将其结果作为消息发送给演员(可能是同一个演员)。
import akka.pattern.pipe
object MyActor {
def doItAsynchronously(implicit ec: ExecutionContext): Future[DoItResult] = {
/* ... */
}
}
class MyActor extends Actor {
import MyActor._
import context.dispatcher
def receive = {
case DoIt =>
doItAsynchronously.pipeTo(self)
case DoItResult =>
// Got a result from doing it
}
}
这可以确保您不会改变演员中的任何状态。
答案 1 :(得分:0)
如果您需要在期货中改变状态而不阻止收到的消息,您可能需要重新考虑重新设计您的演员模型。我将为你将使用这些期货的每个任务引入单独的演员。毕竟,演员的主要任务是保持其状态而不让它逃脱,从而提供安全的并发性。为那些长期运行的任务定义一个actor,其任务只是为了处理它。
您可能需要考虑使用akka's FSM而不是手动处理状态,以便更清楚地了解何时发生的变化。当我处理更复杂的系统时,我当然更喜欢这种方法来处理丑陋的变量。
答案 2 :(得分:0)
记住两件事
术语Future(一个特殊演员)背后的概念是我们可以为任何结果创建一个演员,而它(结果)仍在计算,开始或完成但我们不能拥有该特殊演员或未来的地址。
假设我想购买东西(我的结果是购买东西,以及启动购买程序的步骤)我们可以为结果创建一个演员(购买)但是如果有任何问题我们我们不能购买我们会有例外而不是结果的东西。
以下解释了上述两件事如何适用 -
假设我们需要计算10亿的阶乘,我们可能会认为它需要花费大量时间来计算,但我们立刻得到了Future,它不会花费时间来产生Future(import React, { Component } from 'react';
import './App.css';
import Search from './Search';
import Sidebar from './Sidebar';
class App extends Component {
constructor() {
super()
this.state = {
menu: []
}
}
handleSearchResult = (array) => {
// always the correct value
console.log('in ', array);
this.setState( {menu: menuList})
// 1st call : empty
// 2nd call : previous value not showing on 1st call + new value as expected
// does not trigger <Sidebar list={this.state.menu}/>
console.log('out', this.state.menu);
}
render() {
return (
<div className="App">
// not refreshing
<Search updateMenu={this.handleSearchResult} />
<Sidebar list={this.state.menu}/>
</div>
);
}
}
export default App;
)。接下来,我们可以通过这个未来,存储并分配它。
希望你能理解我想说的话。