猿问
Scala 的 actor 与 Go 的协程相似吗?
如果我想移植一个使用 Goroutines 的 Go 库,Scala 会是一个不错的选择,因为它的 inbox/akka 框架在本质上类似于协程吗?
慕码人2483693
浏览 445
回答 3
3回答
达令说
这里有两个问题:Scala 是移植的好选择goroutines吗?这是一个简单的问题,因为 Scala 是一种通用语言,它并不比您可以选择“移植 goroutines”的许多其他语言更差或更好。当然,关于为什么 Scala作为一种语言更好或更差的原因有很多意见(例如,这是我的),但这些只是意见,不要让它们阻止您。由于 Scala 是通用的,它“几乎”归结为:您可以在语言 X 中做的一切,您都可以在 Scala 中做。如果这听起来太宽泛了…… Java 中的延续怎么样:)Scala 演员与goroutines?唯一的相似之处(除了吹毛求疵)是它们都与并发和消息传递有关。但这就是相似性结束的地方。由于 Jamie 的回答很好地概述了 Scala 演员,因此我将更多地关注 Goroutines/core.async,但会介绍一些演员模型。演员帮助事情“无忧分发”其中“无忧”片通常与诸如有关:fault tolerance,resiliency,availability等。无需深入研究 actor 的工作原理,简单来说,actor 与以下两个术语有关:位置:每个参与者都有一个地址/引用,其他参与者可以使用它来向其发送消息行为:当消息到达参与者时应用/调用的函数想想“谈话进程”,其中每个进程都有一个引用和一个在消息到达时被调用的函数。当然还有更多内容(例如查看Erlang OTP或akka docs),但以上两个是一个好的开始。演员有趣的地方是......实现。目前有两个大的,是 Erlang OTP 和 Scala AKKA。虽然他们都旨在解决同一件事,但还是存在一些差异。让我们看一对夫妇:我故意不使用诸如“引用透明”、“幂等”之类的术语。它们除了造成混乱之外没有任何好处,所以让我们只谈一下不变性[一个can't change that概念]。Erlang 作为一种语言是固执己见的,它倾向于强大的不变性,而在 Scala 中,当接收到消息时,很容易让 actor 改变/改变他们的状态。不推荐这样做,但 Scala 中的可变性就在您面前,人们确实在使用它。Joe Armstrong 谈到的另一个有趣的观点是 Scala/AKKA 受到 JVM 的限制,JVM 的设计并没有真正考虑到“分布式”,而 Erlang VM 是。它与许多事情有关,例如:进程隔离、每个进程与整个 VM 垃圾收集、类加载、进程调度等。上面的重点并不是说一个比另一个更好,而是表明actor模型作为一个概念的纯度取决于它的实现。现在到 goroutines ..Goroutines 有助于按顺序推理并发正如已经提到的其他答案,goroutines 植根于Communicating Sequential Processes,这是一种“用于描述并发系统中交互模式的正式语言”,根据定义,它几乎可以意味着任何事情:)我将给出基于core.async 的示例,因为我比 Goroutines 更了解它的内部结构。但是core.async是在 Goroutines/CSP 模型之后构建的,所以概念上应该不会有太多差异。core.async/Goroutine 中的主要并发原语是一个channel. 将 achannel视为“岩石上的队列”。该通道用于“传递”消息。任何想要“参与游戏”的进程都会创建或获取对 a 的引用,并向其channel发送/接收(例如发送/接收)消息。24 小时免费停车在通道上完成的大部分工作通常发生在“ Goroutine ”或“ go block ”中,它“获取它的主体并检查它是否有任何通道操作。它将把主体变成一个状态机。在到达任何阻塞操作时,状态机将被“停放”并释放实际的控制线程。这种方法类似于 C# async 中使用的方法。当阻塞操作完成时,代码将被恢复(在线程池线程上,或JS VM 中的唯一线程) ”(源代码)。用视觉传达要容易得多。以下是阻塞 IO 执行的样子:您可以看到线程大部分时间都在等待工作。这是相同的工作,但通过“Goroutine”/“go block”方法完成:这里 2 个线程完成了所有工作,4 个线程以阻塞方式完成了所有工作,同时花费了相同的时间。上面描述中的关键是:当它们没有工作时“线程被停放”,这意味着,它们的状态被“卸载”到状态机,而实际的实时 JVM 线程可以自由地做其他工作(一个伟大的视觉来源)注意:在core.async 中,通道可以在“go 块”之外使用,这将由没有停放能力的JVM 线程支持:例如,如果它阻塞,它将阻塞真正的线程。Go 频道的力量“Goroutines”/“go blocks”中另一个重要的事情是可以在通道上执行的操作。例如,可以创建一个超时通道,它将在 X 毫秒内关闭。或选择/ alt!功能,当与许多频道结合使用时,就像跨不同频道的“你准备好了吗”轮询机制一样。将其视为非阻塞 IO 中的套接字选择器。以下是使用timeout channel和的示例alt!:(defn race [q] (searching [:.yahoo :.google :.bing]) (let [t (timeout timeout-ms) start (now)] (go (alt! (GET (str "/yahoo?q=" q)) ([v] (winner :.yahoo v (took start))) (GET (str "/bing?q=" q)) ([v] (winner :.bing v (took start))) (GET (str "/google?q=" q)) ([v] (winner :.google v (took start))) t ([v] (show-timeout timeout-ms))))))此代码片段取自wracer,它向所有三个:Yahoo、Bing 和 Google 发送相同的请求,并返回最快的结果,或者如果在给定时间内没有返回则超时(返回超时消息)。Clojure 可能不是您的第一语言,但您不能不同意这种并发实现的顺序看起来和感觉如何。您还可以从/向多个通道合并/扇入/扇出数据,映射/减少/过滤/...通道数据等等。频道也是一等公民:您可以将频道传递给频道..去 UI 去!由于 core.async “go blocks” 具有“停放”执行状态的能力,并且在处理并发时具有非常顺序的“外观和感觉”,那么 JavaScript 呢?JavaScript 中没有并发,因为只有一个线程,对吧?模拟并发的方式是通过 1024 个回调。但它不一定是这样。来自wracer的上述示例实际上是用 ClojureScript 编写的,可编译为 JavaScript。是的,它可以在具有多个线程的服务器上和/或在浏览器中工作:代码可以保持不变。Goroutines 与 core.async同样,一些实现差异[还有更多]强调了一个事实,即理论概念在实践中并不完全是一对一的:在 Go 中,通道是类型化的,而在 core.async 中则不是:例如,在 core.async 中,您可以将任何类型的消息放在同一个通道上。在 Go 中,你可以将可变的东西放在通道上。不推荐,但你可以。在 core.async 中,由 Clojure 设计,所有数据结构都是不可变的,因此通道内的数据感觉更安全。那么判决结果是什么?我希望以上内容可以说明演员模型和 CSP 之间的差异。不是为了引起一场火焰战争,而是为了给你另一个视角,让我们说 Rich Hickey:"我对演员仍然不感兴趣。他们仍然将生产者与消费者结合起来。是的,可以用演员模拟或实现某些类型的队列(值得注意的是,人们经常这样做),但由于任何演员机制都已经包含了队列,因此显然队列更原始。应该注意的是,Clojure 的并发使用状态的机制仍然可行,并且通道面向系统的流方面。 ”但是,在实践中,Whatsapp 是基于 Erlang OTP 的,它似乎卖得很好。另一个有趣的引用来自 Rob Pike:"缓冲发送不向发送方确认并且可以花费任意长的时间。缓冲通道和 goroutines 非常接近 actor 模型。Actor 模型和 Go 之间的真正区别在于通道是一等公民。同样重要的是:它们是间接的,就像文件描述符而不是文件名,允许在 actor 模型中不容易表达的并发样式。也有相反的情况;我不是在做价值判断。理论上,这些模型是等效的。“
0
0
0
神不在的星期二
将我的一些评论移到答案中。时间太长了:D(不要从 jamie 和 tolitius 的帖子中删除;他们都是非常有用的答案。)在 Akka 中使用 goroutine 可以做完全相同的事情,这并不完全正确。Go 通道通常用作同步点。你不能直接在 Akka 中重现它。在 Akka 中,同步后处理必须移动到单独的处理程序中(用 Jamie 的话来说是“散布”:D)。我会说设计模式是不同的。你可以用 a 启动一个 goroutine chan,做一些事情,然后<-等待它完成再继续。Akka 有一个不那么强大的形式ask,但ask并不是真正的 Akka 方式 IMO。Chans 也被输入,而邮箱则不是。这对 IMO 来说是件大事,对于基于 Scala 的系统来说,这是非常令人震惊的。我知道这become很难用类型化的消息来实现,但这可能表明它become不太像 Scala。关于 Akka,我可以这么说。通常感觉就像它自己的东西恰好在 Scala 上运行。Goroutines 是 Go 存在的一个关键原因。不要误会我的意思;我非常喜欢 actor 模型,我通常喜欢 Akka 并且觉得在其中工作很愉快。我也普遍喜欢 Go(我觉得 Scala 很漂亮,虽然我觉得 Go 只是有用;但它非常有用)。但容错确实是 Akka IMO 的重点。你碰巧获得了并发性。并发是 goroutine 的核心。容错在 Go 中是一个单独的东西,委托给defer和recover,可以用来实现相当多的容错。Akka 的容错更正式、功能更丰富,但也可能更复杂一些。所有人都说,尽管有一些短暂的相似之处,但 Akka 不是 Go 的超集,它们在功能上有很大的不同。Akka 和 Go 在鼓励你解决问题的方式上有很大不同,而在一个方面容易的事情在另一个方面很尴尬、不切实际,或者至少是不习惯的。这是任何系统中的关键区别。因此,将其带回您的实际问题:我强烈建议在将 Go 接口引入 Scala 或 Akka(这也是 IMO 完全不同的东西)之前重新考虑 Go 接口。确保你按照目标环境的方式做事。一个复杂的 Go 库的直接移植很可能不适合这两种环境。
0
0
0
随时随地看视频
慕课网APP
相关分类
Go
我要回答