scala:我们可以 yield/resume actor 就像 goroutine 一样吗?
scala: could we yield/resume actor just like goroutine?
我正在学习 Scala。我很困惑actor和goroutine的区别
众所周知,golang的并发单元是goroutine,并发模型在我看来是非常特别优雅的:
- CPU绑定任务
运行时间调度程序将尽最大努力抢占long-running协程,例如检查函数调用时的抢占,这样long-running协程就不会占用系统线程太久
- 事件驱动调用
例如,在Linux上,epoll 可以管理的所有类型的事件,例如套接字连接,将产生 goroutine 并在稍后调用完成时恢复它。当 goroutine yield 时,持有的线程将被释放以处理下一个就绪的 goroutine
- cgo 调用
此类调用将独占一个系统线程,直到调用 returns。
如何在 scala actor 中处理所有这些类型的调用?
Scala 重用并依赖于 JDK 来访问 low-level 系统调用,对吗?例如网络套接字。一些 high-level 库也在 scala 中重复使用,例如JDBC。 Java 的并发模型是线程(系统线程),Java 中的所有那些调用都会阻塞线程,直到调用 returns。那么如何将它们封装在actor中呢? actor 和 goroutine 的表现有区别吗?
期待专业解答!谢谢!
编辑:
我搜索了一些文档,我猜答案可能是:
- CPU绑定任务
scala 中没有提供抢占
- 事件驱动调用
由于 Akka 已集成到 scala 中,因此是使用 Akka 异步包装库(例如 Akka TCP)还是使用 future?
- cgo 调用
???
我更改此标题post。我已经了解了actor和goroutine的风格区别,我只关心在actor中如何处理不同类型的调用,就像gorotuine一样。
编辑:
抱歉,我终于知道我的问题是什么了:
我们可以 yield/resume actor 就像 goroutine 一样吗?
或者 actor 只是一个预定的计算块,应该从头到尾 运行?即整个消息处理不能中断
而且由于Java中的线程模型,我认为它缺少low-level支持基于协程的阻塞调用,对吧?例如socket read,如果阻塞,yield协程,当有新数据读取到read时,resume协程;虽然它对程序员来说是透明的,但您只需编写 socket.read() 即可。众所周知,在Java中,这整个过程都是基于系统线程的,传统的方式就像C.
如果您想知道的只是如何处理 IO 调用,Future 在 scala 中被认为更加地道。
当你有层次结构模型,或者你想要任何复杂的故障恢复机制时,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
}
我从
那里学到了大部分细节
- https://github.com/alexandru/scala-best-practices/blob/master/sections/4-concurrency-parallelism.md
- http://docs.scala-lang.org/overviews/core/futures.html
编辑1:问题已更新,本次编辑尝试回答新问题
Q: 我们可以yield/resume演员吗?
A:
不太确定我理解的对不对,请问为什么要让位复演员?
您似乎希望控制 运行time 的低级处理细节,我认为这 actor.
无法实现
Actor 是反应性的,这意味着每当您向它发送消息时它都会做一些事情,仅此而已,您无法控制事情的执行方式,同一个 actor 甚至可能 运行 在不同的线程上。
通常,如果我们需要异步操作,我们会将操作包装在 Future
中,但是 Future 不会自动使问题消失,如果您包装在 Future 中的操作阻塞了线程,它仍然会块,但包装在 Future 中会使您的代码异步,即下一行代码可以 运行 而无需等待先前的操作到 return.
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
我正在学习 Scala。我很困惑actor和goroutine的区别
众所周知,golang的并发单元是goroutine,并发模型在我看来是非常特别优雅的:
- CPU绑定任务
运行时间调度程序将尽最大努力抢占long-running协程,例如检查函数调用时的抢占,这样long-running协程就不会占用系统线程太久
- 事件驱动调用
例如,在Linux上,epoll 可以管理的所有类型的事件,例如套接字连接,将产生 goroutine 并在稍后调用完成时恢复它。当 goroutine yield 时,持有的线程将被释放以处理下一个就绪的 goroutine
- cgo 调用
此类调用将独占一个系统线程,直到调用 returns。
如何在 scala actor 中处理所有这些类型的调用?
Scala 重用并依赖于 JDK 来访问 low-level 系统调用,对吗?例如网络套接字。一些 high-level 库也在 scala 中重复使用,例如JDBC。 Java 的并发模型是线程(系统线程),Java 中的所有那些调用都会阻塞线程,直到调用 returns。那么如何将它们封装在actor中呢? actor 和 goroutine 的表现有区别吗?
期待专业解答!谢谢!
编辑:
我搜索了一些文档,我猜答案可能是:
- CPU绑定任务
scala 中没有提供抢占
- 事件驱动调用
由于 Akka 已集成到 scala 中,因此是使用 Akka 异步包装库(例如 Akka TCP)还是使用 future?
- cgo 调用
???
我更改此标题post。我已经了解了actor和goroutine的风格区别,我只关心在actor中如何处理不同类型的调用,就像gorotuine一样。
编辑:
抱歉,我终于知道我的问题是什么了:
我们可以 yield/resume actor 就像 goroutine 一样吗?
或者 actor 只是一个预定的计算块,应该从头到尾 运行?即整个消息处理不能中断
而且由于Java中的线程模型,我认为它缺少low-level支持基于协程的阻塞调用,对吧?例如socket read,如果阻塞,yield协程,当有新数据读取到read时,resume协程;虽然它对程序员来说是透明的,但您只需编写 socket.read() 即可。众所周知,在Java中,这整个过程都是基于系统线程的,传统的方式就像C.
如果您想知道的只是如何处理 IO 调用,Future 在 scala 中被认为更加地道。
当你有层次结构模型,或者你想要任何复杂的故障恢复机制时,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
}
我从
那里学到了大部分细节- https://github.com/alexandru/scala-best-practices/blob/master/sections/4-concurrency-parallelism.md
- http://docs.scala-lang.org/overviews/core/futures.html
编辑1:问题已更新,本次编辑尝试回答新问题
Q: 我们可以yield/resume演员吗?
A: 不太确定我理解的对不对,请问为什么要让位复演员? 您似乎希望控制 运行time 的低级处理细节,我认为这 actor.
无法实现Actor 是反应性的,这意味着每当您向它发送消息时它都会做一些事情,仅此而已,您无法控制事情的执行方式,同一个 actor 甚至可能 运行 在不同的线程上。
通常,如果我们需要异步操作,我们会将操作包装在 Future
中,但是 Future 不会自动使问题消失,如果您包装在 Future 中的操作阻塞了线程,它仍然会块,但包装在 Future 中会使您的代码异步,即下一行代码可以 运行 而无需等待先前的操作到 return.
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