Scala 的 actor 与 Go 的协程相似吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22621514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 06:08:21  来源:igfitidea点击:

Is Scala's actors similar to Go's coroutines?

scalago

提问by loyalflow

If I wanted to port a Go library that uses Goroutines, would Scala be a good choice because its inbox/akka framework is similar in nature to coroutines?

如果我想移植一个使用 Goroutines 的 Go 库,Scala 会是一个不错的选择,因为它的 inbox/akka 框架在本质上类似于协程吗?

回答by jamie

Nope, they're not. Goroutines are based on the theory of Communicating Sequential Processes, as specified by Tony Hoare in 1978. The idea is that there can be two processes or threads that act independently of one another but share a "channel," which one process/thread puts data into and the other process/thread consumes. The most prominent implementations you'll find are Go's channels and Clojure's core.async, but at this time they are limited to the current runtime and cannot be distributed, even between two runtimes on the same physical box.

不,他们不是。Goroutines 基于 Communicating Sequential Processes 理论,由 Tony Hoare 在 1978 年指定。这个想法是可以有两个进程或线程,它们彼此独立运行但共享一个“通道”,一个进程/线程将数据放入其中进入和另一个进程/线程消耗。您会发现最突出的实现是 Go 的通道和 Clojure 的core.async,但此时它们仅限于当前运行时,不能分发,即使在同一个物理机器上的两个运行时之间也是如此。

CSP evolved to include a static, formal process algebra for proving the existence of deadlocks in code. This is a really nice feature, but neither Goroutines nor core.asynccurrently support it. If and when they do, it will be extremely nice to know before running your code whether or not a deadlock is possible. However, CSP does not support fault tolerance in a meaningful way, so you as the developer have to figure out how to handle failure that can occur on both sides of channels, and such logic ends up getting strewn about all over the application.

CSP 演变为包含一个静态的、正式的过程代数,用于证明代码中死锁的存在。这是一个非常好的功能,但 Goroutines 和core.async当前都不支持它。如果他们这样做,那么在运行您的代码之前知道是否可能发生死锁会非常好。但是,CSP 并不以有意义的方式支持容错,因此您作为开发人员必须弄清楚如何处理可能发生在通道两侧的故障,而这种逻辑最终会散布在整个应用程序中。

Actors, as specified by Carl Hewitt in 1973, involve entities that have their own mailbox. They are asynchronous by nature, and have location transparency that spans runtimes and machines - if you have a reference (Akka) or PID (Erlang) of an actor, you can message it. This is also where some people find fault in Actor-based implementations, in that you have to have a reference to the other actor in order to send it a message, thus coupling the sender and receiver directly. In the CSP model, the channel is shared, and can be shared by multiple producers and consumers. In my experience, this has not been much of an issue. I like the idea of proxy references that mean my code is not littered with implementation details of how to send the message - I just send one, and wherever the actor is located, it receives it. If that node goes down and the actor is reincarnated elsewhere, it's theoretically transparent to me.

演员,正如卡尔休伊特在 1973 年所指定的,涉及拥有自己邮箱的实体。它们本质上是异步的,并且具有跨越运行时和机器的位置透明度——如果您有一个参与者的引用 (Akka) 或 PID (Erlang),您可以向它发送消息。这也是一些人在基于 Actor 的实现中发现错误的地方,因为您必须拥有对另一个 Actor 的引用才能向它发送消息,从而直接耦合发送方和接收方。在CSP模型中,通道是共享的,可以被多个生产者和消费者共享。根据我的经验,这不是什么大问题。我喜欢代理引用的想法,这意味着我的代码不会充斥着如何发送消息的实现细节——我只发送一个,无论演员位于哪里,它都会接收它。

Actors have another very nice feature - fault tolerance. By organizing actors into a supervision hierarchy per the OTP specification devised in Erlang, you can build a domain of failure into your application. Just like value classes/DTOs/whatever you want to call them, you can model failure, how it should be handled and at what level of the hierarchy. This is very powerful, as you have very little failure handling capabilities inside of CSP.

Actors 还有一个非常好的特性——容错。通过按照 Erlang 中设计的 OTP 规范将参与者组织到监督层次结构中,您可以在应用程序中构建故障域。就像值类/DTO/任何你想调用它们的东西一样,你可以对失败、应该如何处理以及在层次结构的哪个级别进行建模。这非常强大,因为您在 CSP 内部几乎没有故障处理能力。

Actors are also a concurrency paradigm, where the actor can have mutable state inside of it and a guarantee of no multithreaded access to the state, unless the developer building an actor-based system accidentally introduces it, for example by registering the Actor as a listener for a callback, or going asynchronous inside the actor via Futures.

Actors 也是一种并发范式,Actor 内部可以有可变状态,并保证没有多线程访问该状态,除非构建基于 Actor 的系统的开发人员不小心引入了它,例如通过将 Actor 注册为侦听器用于回调,或通过 Futures 在 actor 内部进行异步处理。

Shameless plug - I'm writing a new book with the head of the Akka team, Roland Kuhn, called Reactive Design Patterns where we discuss all of this and more. Green threads, CSP, event loops, Iteratees, Reactive Extensions, Actors, Futures/Promises, etc. Expect to see a MEAP on Manning by early next month.

无耻的插件 - 我正在与 Akka 团队的负责人 Roland Kuhn 一起写一本名为 Reactive Design Patterns 的新书,我们将在其中讨论所有这些以及更多内容。绿色线程、CSP、事件循环、迭代器、反应式扩展、Actor、Futures/Promises 等。预计在下个月初之前会看到关于 Manning 的 MEAP。

Good luck!

祝你好运!

回答by tolitius

There are two questions here:

这里有两个问题:

  • Is Scala a good choice to port goroutines?
  • Scala 是移植的好选择goroutines吗?

This is an easy question, since Scala is a general purpose language, which is no worse or better than many others you can choose to "port goroutines".

这是一个简单的问题,因为 Scala 是一种通用语言,它并不比您可以选择“移植 goroutines”的许多其他语言更差或更好。

There are of course many opinionson why Scala is better or worse as a language(e.g. hereis mine), but these are just opinions, and don't let them stop you. Since Scala is general purpose, it "pretty much" comes down to: everything you can do in language X, you can do in Scala. If it sounds too broad.. how about continuations in Java:)

当然,关于为什么 Scala作为一种语言更好或更差的原因有很多意见(例如,是我的),但这些只是意见,不要让它们阻止您。由于 Scala 是通用的,它“几乎”归结为:您可以在语言 X 中做的一切,您都可以在 Scala 中做。如果这听起来太宽泛了…… Java 中的延续怎么样:)

  • Are Scala actors similar to goroutines?
  • Scala 演员与goroutines?

The only similarity (aside the nitpicking) is they both have to do with concurrency and message passing. But that is where the similarity ends.

唯一的相似之处(除了吹毛求疵)是它们都与并发和消息传递有关。但这就是相似性结束的地方。

Since Jamie's answer gave a good overview of Scala actors, I'll focus more on Goroutines/core.async, but with some actor model intro.

由于 Jamie 的回答很好地概述了 Scala 演员,因此我将更多地关注 Goroutines/core.async,但会介绍一些演员模型。

Actors help things to be "worry free distributed"

演员帮助事情“无忧分发”



Where a "worry free" piece is usually associated with terms such as: fault tolerance, resiliency, availability, etc..

其中“无忧”片通常与诸如有关:fault toleranceresiliencyavailability等。

Without going into grave details how actors work, in two simple terms actors have to do with:

在不深入研究演员如何工作的细节的情况下,用两个简单的术语来说,演员必须与:

  • Locality: each actor has an address/reference that other actors can use to send messages to
  • Behavior: a function that gets applied/called when the message arrives to an actor
  • 位置:每个参与者都有一个地址/引用,其他参与者可以使用它来向其发送消息
  • 行为:当消息到达演员时应用/调用的函数

Think "talking processes" where each process has a reference and a function that gets called when a message arrives.

想想“谈话进程”,其中每个进程都有一个引用和一个在消息到达时被调用的函数。

There is much more to it of course (e.g. check out Erlang OTP, or akka docs), but the above two is a good start.

当然还有更多内容(例如查看Erlang OTPakka docs),但以上两个是一个好的开始。

Where it gets interesting with actors is.. implementation. Two big ones, at the moment, are Erlang OTP and Scala AKKA. While they both aim to solve the same thing, there are some differences. Let's look at a couple:

演员的有趣之处在于......实现。目前有两个大的,是 Erlang OTP 和 Scala AKKA。虽然他们都旨在解决同一件事,但还是存在一些差异。让我们看一对夫妇:

  • I intentionally do not use lingo such as "referential transparency", "idempotence", etc.. they do no good besides causing confusion, so let's just talk about immutability [a can't change thatconcept]. Erlang as a language is opinionated, and it leans towards strong immutability, while in Scala it is too easy to make actors that change/mutate their state when a message is received. It is not recommended, but mutability in Scala is right there in front of you, and people douse it.

  • Another interesting point that Joe Armstrong talks about is the fact that Scala/AKKA is limited by the JVM which just wasn't really designed with "being distributed" in mind, while Erlang VM was. It has to do with many things such as: process isolation, per process vs. the whole VM garbage collection, class loading, process scheduling and others.

  • 我故意不使用诸如“引用透明”、“幂等”之类的术语。它们除了引起混乱之外没有任何好处,所以让我们只谈一下不变性[一个can't change that概念]。Erlang 作为一种语言是固执己见的,它倾向于强大的不变性,而在 Scala 中,当接收到消息时,很容易让 actor 改变/改变他们的状态。不推荐这样做,但是 Scala 中的可变性就在您面前,人们确实在使用它。

  • Joe Armstrong 谈到的另一个有趣的观点是,Scala/AKKA 受到 JVM 的限制,JVM 的设计并没有真正考虑到“分布式”,而 Erlang VM 是。它与许多事情有关,例如:进程隔离、每个进程与整个 VM 垃圾收集、类加载、进程调度等。

The point of the above is not to say that one is better than the other, but it's to show that purity of the actor model as a concept depends on its implementation.

上面的重点并不是说一个比另一个更好,而是表明actor模型作为一个概念的纯度取决于它的实现。

Now to goroutines..

现在到 goroutines ..

Goroutines help to reason about concurrency sequentially

Goroutines 有助于按顺序推理并发



As other answers already mentioned, goroutines take roots in Communicating Sequential Processes, which is a "formal language for describing patterns of interaction in concurrent systems", which by definition can mean pretty much anything :)

正如已经提到的其他答案,goroutines 植根于Communicating Sequential Processes,这是一种“用于描述并发系统中交互模式的正式语言”,根据定义,它几乎可以意味着任何事情:)

I am going to give examples based on core.async, since I know internals of it better than Goroutines. But core.asyncwas built after the Goroutines/CSP model, so there should not be too many differences conceptually.

我将给出基于core.async 的示例,因为我比 Goroutines 更了解它的内部结构。但是core.async是在 Goroutines/CSP 模型之后构建的,所以概念上应该不会有太多差异。

The main concurrency primitive in core.async/Goroutine is a channel. Think about a channelas a "queue on rocks". This channel is used to "pass" messages. Any process that would like to "participate in a game" creates or gets a reference to a channeland puts/takes (e.g. sends/receives) messages to/from it.

core.async/Goroutine 中的主要并发原语是一个channel. 将 achannel视为“岩石上的队列”。该通道用于“传递”消息。任何想要“参与游戏”的进程都会创建或获取对 a 的引用,并向其channel发送/接收(例如发送/接收)消息。

Free 24 hour Parking

24小时免费停车

Most of work that is done on channels usually happens inside a "Goroutine" or "go block", which "takes its body and examines it for any channel operations. It will turn the body into a state machine. Upon reaching any blocking operation, the state machine will be 'parked' and the actual thread of control will be released. This approach is similar to that used in C# async. When the blocking operation completes, the code will be resumed (on a thread-pool thread, or the sole thread in a JS VM)" (source).

在通道上完成的大部分工作通常发生在“ Goroutine”或“ go block”中,它“获取其主体并检查其是否有任何通道操作。它将主体变成状态机。在达到任何阻塞操作时,状态机将被“停放”并释放实际的控制线程。这种方法类似于 C# 异步中使用的方法。当阻塞操作完成时,代码将被恢复(在线程池线程上,或JS VM 中的唯一线程)”(源代码)。

It is a lot easier to convey with a visual. Here is what a blocking IO execution looks like:

用视觉传达要容易得多。下面是阻塞 IO 执行的样子:

blocking IO

阻塞IO

You can see that threads mostly spend time waiting for work. Here is the same work but done via "Goroutine"/"go block" approach:

您可以看到线程大部分时间都在等待工作。这是相同的工作,但通过“Goroutine”/“go block”方法完成:

core.async

核心异步

Here 2 threads did all the work, that 4 threads did in a blocking approach, while taking the same amount of time.

这里 2 个线程完成了所有工作,4 个线程以阻塞方式完成了所有工作,同时花费了相同的时间。

The kicker in above description is: "threads are parked" when they have no work, which means, their state gets "offloaded" to a state machine, and the actual live JVM thread is free to do other work (sourcefor a great visual)

上面描述中的关键是:当线程没有工作时,“线程被停放”,这意味着,它们的状态被“卸载”到状态机,而实际的实时 JVM 线程可以自由地做其他工作(一个伟大的视觉来源)

note: in core.async, channel can beused outside of "go block"s, which will be backed by a JVM thread without parking ability: e.g. if it blocks, it blocks the real thread.

注意:在 core.async 中,通道可以在“go 块”之外使用,它将由没有停车能力的 JVM 线程支持:例如,如果它阻塞,它将阻塞真正的线程。

Power of a Go Channel

Go 频道的力量

Another huge thing in "Goroutines"/"go blocks" is operations that can be performed on a channel. For example, a timeout channelcan be created, which will close in X milliseconds. Or select/alt!function that, when used in conjunction with many channels, works like a "are you ready" polling mechanism across different channels. Think about it as a socket selector in non blocking IO. Here is an example of using timeout channeland alt!together:

“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))))))

This code snippet is taken from wracer, where it sends the same request to all three: Yahoo, Bing and Google, and returns a result from the fastest one, ortimes out (returns a timeout message) if none returned within a given time. Clojure may not be your first language, but you can't disagree on how sequentialthis implementation of concurrency looks and feels.

此代码片段取自wracer,它向所有三个:Yahoo、Bing 和 Google 发送相同的请求,并返回最快的结果,或者如果在给定时间内没有返回则超时(返回超时消息)。Clojure 可能不是您的第一语言,但您不能不同意这种并发实现的顺序看起来和感觉如何。

You can also merge/fan-in/fan-out data from/to many channels, map/reduce/filter/... channels data and more. Channels are also first class citizens: you can pass a channel to a channel..

您还可以从/向多个通道合并/扇入/扇出数据,映射/减少/过滤/...通道数据等等。频道也是一等公民:您可以将频道传递给频道..

Go UI Go!

去 UI 去!

Since core.async "go blocks" has this ability to "park" execution state, and have a very sequential "look and feel" when dealing with concurrency, how about JavaScript? There is no concurrency in JavaScript, since there is only one thread, right? And the way concurrency is mimicked is via 1024 callbacks.

由于 core.async “go blocks” 具有“停放”执行状态的能力,并且在处理并发时具有非常顺序的“外观和感觉”,那么 JavaScript 呢?JavaScript 中没有并发,因为只有一个线程,对吧?模拟并发的方式是通过 1024 个回调。

But it does not have to be this way. The above example from wraceris in fact written in ClojureScript that compiles down to JavaScript. Yes, it will work on the server with many threads and/or in a browser: the code can stay the same.

但它不一定是这样。来自wracer的上述示例实际上是用 ClojureScript 编写的,可编译为 JavaScript。是的,它可以在具有多个线程的服务器上和/或在浏览器中工作:代码可以保持不变。

Goroutines vs. core.async

Goroutines 与 core.async

Again, a couple of implementation differences [there are more] to underline the fact that theoretical concept is not exactly one to one in practice:

同样,一些实现差异 [还有更多] 强调了一个事实,即理论概念在实践中并不完全是一对一的:

  • In Go, a channel is typed, in core.async it is not: e.g. in core.async you can put messages of any type on the same channel.
  • In Go, you can put mutable things on a channel. It is not recommended, but you can. In core.async, by Clojure design, all data structures are immutable, hence data inside channels feels a lot safer for its wellbeing.
  • 在 Go 中,通道是类型化的,而在 core.async 中则不是:例如,在 core.async 中,您可以将任何类型的消息放在同一个通道上。
  • 在 Go 中,你可以把可变的东西放在一个通道上。不推荐,但你可以。在 core.async 中,由 Clojure 设计,所有数据结构都是不可变的,因此通道内的数据感觉更安全。

So what's the verdict?

那么判决结果是什么?



I hope the above shed some light on differences between the actor model and CSP.

我希望以上内容可以说明演员模型和 CSP 之间的差异。

Not to cause a flame war, but to give you yet another perspective of let's say Rich Hickey:

不是要引起一场激烈的War,而是要给你另一个视角,让我们说 Rich Hickey:

"I remain unenthusiastic about actors. They still couple the producer with the consumer. Yes, one can emulate or implement certain kinds of queues with actors (and, notably, people often do), but since any actor mechanism already incorporates a queue, it seems evident that queues are more primitive. It should be noted that Clojure's mechanisms for concurrent use of state remain viable, and channels are oriented towards the flow aspects of a system."(source)

"我对 actor 仍然不感兴趣。他们仍然将生产者与消费者结合起来。是的,人们可以用 actor 模拟或实现某些类型的队列(尤其是人们经常这样做),但是由于任何 actor 机制都已经包含了一个队列,它显然队列更原始。应该注意的是,Clojure 的状态并发使用机制仍然可行,并且通道面向系统的流方面。”(来源

However, in practice, Whatsapp is based on Erlang OTP, and it seemed to sell pretty well.

但是在实践中,Whatsapp 是基于 Erlang OTP 的,它似乎卖得很好。

Another interesting quote is from Rob Pike:

另一个有趣的引用来自 Rob Pike:

"Buffered sends are not confirmed to the sender and can take arbitrarily long. Buffered channels and goroutines are very close to the actor model.

"缓冲发送不向发送方确认并且可以花费任意长的时间。缓冲通道和 goroutines 非常接近 actor 模型。

The real difference between the actor model and Go is that channels are first-class citizens. Also important: they are indirect, like file descriptors rather than file names, permitting styles of concurrency that are not as easily expressed in the actor model. There are also cases in which the reverse is true; I am not making a value judgement. In theory the models are equivalent."(source)

Actor 模型和 Go 之间的真正区别在于通道是一等公民。同样重要的是:它们是间接的,就像文件描述符而不是文件名,允许在actor模型中不容易表达的并发样式。也有相反的情况;我不是在做价值判断。理论上,这些模型是等效的。“(来源

回答by Rob Napier

Moving some of my comments to an answer. It was getting too long :D (Not to take away from jamie and tolitius's posts; they're both very useful answers.)

将我的一些评论移到答案中。时间太长了:D(不要从 jamie 和 tolitius 的帖子中删除;他们都是非常有用的答案。)

It isn't quite true that you could do the exact same things that you do with goroutines in Akka. Go channels are often used as synchronization points. You cannot reproduce that directly in Akka. In Akka, post-sync processing has to be moved into a separate handler ("strewn" in jamie's words :D). I'd say the design patterns are different. You can kick off a goroutine with a chan, do some stuff, and then <-to wait for it to finish before moving on. Akka has a less-powerful form of this with ask, but askisn't really the Akka way IMO.

在 Akka 中使用 goroutine 可以做完全相同的事情,这并不完全正确。Go 通道通常用作同步点。你不能直接在 Akka 中重现它。在 Akka 中,同步后处理必须移动到单独的处理程序中(用 Jamie 的话来说是“散布”:D)。我会说设计模式是不同的。你可以用 a 启动一个 goroutine chan,做一些事情,然后<-等待它完成再继续。Akka 有一个不那么强大的形式ask,但ask并不是真正的 Akka 方式 IMO。

Chans are also typed, while mailboxes are not. That's a big deal IMO, and it's pretty shocking for a Scala-based system. I understand that becomeis hard to implement with typed messages, but maybe that indicates that becomeisn't very Scala-like. I could say that about Akka generally. It often feels like its own thing that happens to run on Scala. Goroutines are a key reason Go exists.

Chans 也被输入,而邮箱则不是。这对 IMO 来说是件大事,对于基于 Scala 的系统来说,这是非常令人震惊的。我知道这become很难用类型化的消息来实现,但这可能表明它become不太像 Scala。我可以这样说一般的 Akka。通常感觉就像它自己的东西恰好在 Scala 上运行。Goroutines 是 Go 存在的一个关键原因。

Don't get me wrong; I like the actor model a lot, and I generally like Akka and find it pleasant to work in. I also generally like Go (I find Scala beautiful, while I find Go merely useful; but it is quite useful).

不要误会我的意思;我非常喜欢 actor 模型,我通常喜欢 Akka 并且觉得在其中工作很愉快。我也普遍喜欢 Go(我觉得 Scala 很漂亮,虽然我觉得 Go 只是有用;但它非常有用)。

But fault tolerance is really the point of Akka IMO. You happen to get concurrency with that. Concurrency is the heart of goroutines. Fault-tolerance is a separate thing in Go, delegated to deferand recover, which can be used to implement quite a bit of fault tolerance. Akka's fault tolerance is more formal and feature-rich, but it can also be a bit more complicated.

但容错确实是 Akka IMO 的重点。你碰巧获得了并发性。并发是 goroutine 的核心。容错在 Go 中是一个单独的东西,委托给deferrecover,可以用来实现相当多的容错。Akka 的容错更正式、功能更丰富,但也可能更复杂一些。

All said, despite having some passing similarities, Akka is not a superset of Go, and they have significant divergence in features. Akka and Go are quite different in how they encourage you to approach problems, and things that are easy in one, are awkward, impractical, or at least non-idiomatic in the other. And that's the key differentiators in any system.

所有人都说,尽管有一些短暂的相似之处,但 Akka 不是 Go 的超集,它们在功能上有很大的不同。Akka 和 Go 在鼓励您解决问题的方式上有很大不同,而在一个方面容易的事情在另一个方面很尴尬、不切实际,或者至少是不习惯的。这是任何系统中的关键区别。

So bringing it back to your actual question: I would strongly recommend rethinking the Go interface before bringing it to Scala or Akka (which are also quite different things IMO). Make sure you're doing it the way your target environment means to do things. A straight port of a complicated Go library is likely to not fit in well with either environment.

所以把它带回你的实际问题:我强烈建议在将 Go 接口带到 Scala 或 Akka(这也是 IMO 完全不同的东西)之前重新考虑 Go 接口。确保您按照目标环境的方式进行操作。一个复杂的 Go 库的直接移植很可能不适合这两种环境。

回答by DragonFax

These are all great and thorough answers. But for a simple way to look at it, here is my view. Goroutines are a simple abstraction of Actors. Actors are just a more specific use-case of Goroutines.

这些都是伟大而彻底的答案。但为了简单地看待它,这是我的观点。Goroutines 是对 Actor 的简单抽象。Actors 只是 Goroutines 的一个更具体的用例。

You could implement Actors using Goroutines by creating the Goroutine aside a Channel. By deciding that the channel is 'owned' by that Goroutine you're saying that only that Goroutine will consume from it. Your Goroutine simply runs an inbox-message-matching loop on that Channel. You can then simply pass the Channel around as the 'address' of your "Actor" (Goroutine).

您可以通过在 Channel 旁边创建 Goroutine 来使用 Goroutines 来实现 Actor。通过决定该通道由该 Goroutine “拥有”,您是说只有该 Goroutine 会从中消费。您的 Goroutine 只是在该频道上运行一个收件箱消息匹配循环。然后,您可以简单地将 Channel 作为“Actor”(Goroutine)的“地址”传递。

But as Goroutines are an abstraction, a more general design than actors, Goroutines can be used for far more tasks and designs than Actors.

但是由于 Goroutines 是一种抽象,比 Actors 更通用的设计,Goroutines 可以用于比 Actors 多得多的任务和设计。

A trade-off though, is that since Actors are a more specific case, implementations of actors like Erlang can optimize them better (rail recursion on the inbox loop) and can provide other built-in features more easily (multi process and machine actors).

但需要权衡的是,由于 Actors 是一个更具体的案例,像 Erlang 这样的 Actor 的实现可以更好地优化它们(收件箱循环上的轨道递归),并且可以更轻松地提供其他内置功能(多进程和机器 Actor) .

回答by weima

can we say that in Actor Model, the addressable entity is the Actor, the recipient of message. whereas in Go channels, the addressable entity is the channel, the pipe in which message flows.

可以说在Actor Model中,可寻址的实体是Actor,消息的接收者。而在 Go 通道中,可寻址实体是通道,消息在其中流动的管道。

in Go channel, you send message to the channel, and any number of recipients can be listening, and one of them will receive the message.

在 Go 频道中,您向频道发送消息,任何数量的收件人都可以收听,其中一个将收到消息。

in Actor only one actor to whose actor-ref you send the message, will receive the message.

在 Actor 中,只有您向其 actor-ref 发送消息的一个 actor 会收到该消息。