斯卡拉:我们能像goroutine那样屈服/恢复演员吗?

时间:2016-05-26 14:04:45

标签: scala actor

我正在学习scala。我对actor和goroutine之间的区别非常困惑。

众所周知,golang的并发单元是goroutine,并且我认为并发模型非常特殊和优雅:

  • CPU绑定任务

运行时调度程序将尽最大努力抢占长时间运行的协同程序,例如:检查函数调用的抢占,以便长时间运行的协程不会占用系统线程太长

  • 事件驱动的电话

例如,在Linux上,可以由epoll管理的所有类型的事件,例如,套接字连接,将产生goroutine并在稍后调用完成后恢复它。当goroutine产生时,保持线程将被释放以处理下一个准备好的goroutine

  • cgo calls

这些调用将专门占用一个系统线程,直到调用返回。

如何在scala actor中处理所有这些类型的调用?

scala重用并依赖于JDK来访问低级系统调用,对吧?例如网络套接字。并且一些高级库也在scala中重用,例如JDBC。 Java的并发模型是线程(系统线程),Java中的所有调用都会在调用返回之前阻塞线程。那么如何将它们封装在actor中呢?演员表演与goroutine不同吗?

期待任何专业的答案!谢谢!

修改

我搜索了一些文件,我想答案可能是:

  • CPU绑定任务

scala中没有提供抢占

  • 事件驱动的电话

由于Akka被集成到scala中,所以要么使用Akka异步包装库(例如Akka TCP)还是使用未来?

  • cgo calls

???

我更改了这篇文章的标题。我已经理解了actor和goroutine之间的风格区别,我只关心如何在actor中处理不同类型的调用,就像gorotuine一样。

修改

抱歉,最后我发现了我的问题:

我们可以像goroutine那样产生/恢复演员吗?

或者演员只是一个应该从头到尾运行的预定计算部分?即整个消息处理无法中断。

由于Java中的线程模型,我认为缺乏基于协同程序阻止调用的低级支持,对吧?例如socket读取,如果是块,则产生协程,当新数据读取时读取,恢复协程;虽然它对程序员来说是透明的,但你需要编写的只是socket.read()。众所周知,在Java中,整个过程基于系统线程,传统方式就像C。

1 个答案:

答案 0 :(得分:2)

如果您只想知道如何处理IO调用,那么在Scala中,Future被认为更加惯用。

当你有一个层次模型,或者你想要任何复杂的故障恢复机制时,Akka是好的,但如果你想做的只是IO,Future就足够了,而且更简单。

此外,IO调用可以是阻塞或非阻塞(在线程级别),您需要单独处理它。幸运的是,它就像

一样简单
Future {
  // non-blocking IO call
} 

import scala.concurrent.blocking
Future {
  blocking {
    ... some blocking IO call
  }
}

如果您需要执行大量IO阻止调用,请使用单独的ExecutionContext

并且不要将CPU绑定任务包装在Future中,CPU绑定意味着您的程序将因Future而无法受益。如果您需要Future来匹配界面,请使用

Future.successful {
  // computation
}

我从

了解了大部分细节
  1. https://github.com/alexandru/scala-best-practices/blob/master/sections/4-concurrency-parallelism.md
  2. http://docs.scala-lang.org/overviews/core/futures.html
  3. 编辑1:问题已更新,此编辑尝试回答新问题

    :我们可以屈服/恢复演员?

    <强> A : 我不太确定我是否理解正确,我可能知道你为什么要屈服并恢复一个演员? 您似乎希望控制运行时的低级处理细节,我认为对于actor 无法实现。

    Actor是被动的,意味着每当你向它发送消息时它都会做某事,而这就是你无法控制事情的执行方式,同一个actor甚至可以在不同的线程上运行。

    通常,如果我们需要异步操作,我们将操作包装在Future中,但是未来不会自动使问题消失,如果你的操作包含在Future中阻塞了线程,它仍会阻塞,但是在Future中包装会使你的代码异步,即下一行代码可以在不等待先前操作返回的情况下运行。

    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext.Implicits.global
    import java.lang.Thread
    
    Future {
      Thread.sleep(1000)
      println("Woke up")
    }
    
    println("Sleeping")
    

    结果将是

    Sleeping
    Woke up