Scala 在Akka I/O是如何工作的?
当您需要执行I/O(即数据库操作)时,actor模型(在Akka中)是如何工作的 我的理解是,阻塞操作将抛出异常(并且由于Akka使用的Netty的事件性质,基本上破坏了所有并发)。因此,我必须使用Scala 在Akka I/O是如何工作的?,scala,scalability,websocket,actor,akka,Scala,Scalability,Websocket,Actor,Akka,当您需要执行I/O(即数据库操作)时,actor模型(在Akka中)是如何工作的 我的理解是,阻塞操作将抛出异常(并且由于Akka使用的Netty的事件性质,基本上破坏了所有并发)。因此,我必须使用未来的或类似的东西-但是我不理解并发模型 一个参与者可以同时处理多条消息吗 如果参与者在future(即future.get())中进行阻塞调用,则该操作是否仅阻塞当前参与者的执行;或者在阻塞调用完成之前,它会阻止所有参与者执行吗 如果它阻止了所有的执行,那么使用将来的辅助并发性(即,将来调用阻塞调用
未来的或类似的东西-但是我不理解并发模型
一个参与者可以同时处理多条消息吗
如果参与者在future
(即future.get()
)中进行阻塞调用,则该操作是否仅阻塞当前参与者的执行;或者在阻塞调用完成之前,它会阻止所有参与者执行吗
如果它阻止了所有的执行,那么使用将来的辅助并发性(即,将来调用阻塞调用是否仍然等于创建一个参与者并执行阻塞调用)
处理多阶段过程(即从数据库读取;调用阻塞Web服务;从数据库读取;向数据库写入)的最佳方法是什么,其中每个步骤都依赖于最后一个步骤
基本情况如下:
- 我正在使用一个Websocket服务器,它将维护数千个会话李>
- 每个会话都有一些状态(即身份验证详细信息等)李>
- Javascript客户端将向服务器发送一条JSON-RPC消息,服务器将把消息传递给适当的会话参与者,会话参与者将执行该消息并返回结果
- RPC调用的执行将涉及一些I/O和阻塞调用
- 将有大量并发请求(每个用户将通过WebSocket连接发出大量请求,并且将有大量用户)
有更好的方法实现这一点吗?阻塞操作不会在Akka中引发异常。您可以阻止来自参与者的呼叫(您可能希望将其最小化,但这是另一种情况)
否,无法创建1个参与者实例李>
它不会阻止任何其他演员。您可以通过使用特定的调度程序来影响这一点。Futures使用默认的dispatcher(通常是全局事件驱动的),因此它在池中的线程上运行。您可以选择要为参与者使用的调度程序(每个参与者或所有参与者)。我想,如果你真的想制造一个问题,你也许可以将完全相同的(基于线程的)分派器传递给未来和参与者,但这会让你的角色产生一些意图。我想如果你有大量的期货无限期阻塞,并且executorservice被配置为固定数量的线程,你可能会毁掉executorservice。所以有很多“如果”。只有在未来尚未完成的情况下才能获得区块。它将阻止您调用它的参与者的“当前线程”(如果您从参与者调用它,顺便说一下,这不是必需的)
你不一定要阻止。您可以使用回调而不是f.get。你甚至可以在不阻塞的情况下编写未来。查看维克多关于“阿克卡光明未来”的演讲,了解更多详情:
我会在步骤之间使用异步通信(如果步骤本身就是有意义的进程),因此在每个步骤中都使用一个参与者,其中每个参与者向下一个发送一条单向消息,也可能是向其他参与者发送一条单向消息,这些参与者不会阻止可以监督进程的进程。通过这种方式,您可以创建多个参与者链,在其前面可以放置一个负载平衡参与者,这样,如果一个参与者在一个链中阻塞,那么相同类型的另一个参与者可能不在另一个链中。这也适用于您的“上下文”问题,将工作负载传递给本地参与者,并将它们链接到负载平衡参与者后面
至于netty(我想你指的是远程演员,因为这是netty在Akka中唯一的用途),如果你担心时间安排或妨碍netty以某种方式完成工作,请尽快将你的工作转交给本地演员或未来(回拨) 阻塞操作通常不会引发异常,但等待将来(例如使用!!
或!!!
发送方法)会引发超时异常。这就是为什么您应该坚持使用fire,并尽可能多地忘记,使用有意义的超时值,并在可能的情况下选择回调
akka参与者无法显式处理一行中的多条消息,但您可以通过配置文件使用throughput
值。然后,如果参与者的消息队列不为空,则参与者将处理多条消息(即,其接收方法将按顺序调用多次):
在一个actor内阻塞操作不会“阻塞”所有actor,但如果在actor之间共享线程(推荐使用),则在操作恢复之前,将阻塞dispatcher的一个线程。因此,尽可能多地编写期货,并注意超时值)
3和4。我同意Raymond的回答。Raymond和paradigmatic所说的,但是,如果您想避免线程池耗尽,您应该将所有阻塞操作包装在scala.concurrent.blocking
中
当然,最好避免阻塞操作,但有时需要使用阻塞的库。如果您将所述代码包装在阻塞中
,它将让执行上下文知道您可能正在阻塞此线程,以便它可以在需要时分配另一个线程
这个问题比paradigmatic描述的更糟糕,因为如果您有几个阻塞操作,那么最终可能会阻塞线程池中的所有线程,而没有空闲线程。如果您的所有线程都被阻塞,而这些阻塞在另一个参与者/未来被调度之前是不会发生的,那么最终可能会导致死锁
下面是一个例子:
import scala.concurrent.blocking
...
Future {
val image = blocking { load_image_from_potentially_slow_media() }
val enhanced = image.enhance()
blocking {
if (oracle.queryBetter(image, enhanced)) {
write_new_image(enhanced)
}
}
enhanced
}
导入scala.concurrent.blocking
...
未来{
val image=阻止{load_image_from_low_low_media()}
val enhanced=image.enhanced()
阻塞{
如果