Scala的actors和Go的coroutines相似吗?

huangapple go评论78阅读模式
英文:

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

问题

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

英文:

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?

答案1

得分: 161

不,它们不是。 Goroutines基于1978年Tony Hoare指定的"通信顺序进程"理论。其思想是可以有两个独立运行但共享一个"通道"的进程或线程,其中一个进程/线程将数据放入通道,另一个进程/线程从通道中消费数据。你会发现最常见的实现是Go语言的通道和Clojure的core.async,但目前它们仅限于当前运行时,不能在同一台物理机上的两个运行时之间进行分布。

CSP发展到包括一种静态的、形式化的进程代数,用于证明代码中死锁的存在。这是一个非常好的特性,但是Goroutines和core.async目前都不支持它。如果它们支持,那么在运行代码之前就能知道是否可能发生死锁将非常好。然而,CSP不以有意义的方式支持容错性,因此作为开发者,你必须找出如何处理可能发生在通道两端的故障,并且这样的逻辑会散布在整个应用程序中。

1973年Carl Hewitt指定的Actor涉及具有自己邮箱的实体。它们天生是异步的,并且具有跨运行时和机器的位置透明性 - 如果你有一个参考(Akka)或PID(Erlang)的Actor,你可以向它发送消息。这也是一些人对基于Actor的实现提出批评的地方,因为你必须拥有对其他Actor的引用才能发送消息,从而直接耦合了发送者和接收者。在CSP模型中,通道是共享的,可以由多个生产者和消费者共享。根据我的经验,这并不是一个大问题。我喜欢代理引用的概念,这意味着我的代码不会被发送消息的实现细节所淹没 - 我只发送一条消息,无论Actor位于何处,它都会接收到。如果该节点崩溃并且Actor在其他地方重新启动,理论上对我来说是透明的。

Actor还有另一个非常好的特性 - 容错性。通过按照Erlang中OTP规范制定的方式将Actor组织成监督层次结构,你可以在应用程序中构建一个故障域。就像值类/DTO/无论你想如何称呼它们,你可以对故障进行建模,定义应该如何处理以及在层次结构的哪个级别处理。这非常强大,因为在CSP内部几乎没有故障处理能力。

Actor也是一种并发模型,其中Actor可以在其内部具有可变状态,并且保证没有多线程访问该状态,除非构建基于Actor的系统的开发者意外引入它,例如将Actor注册为回调的侦听器,或者在Actor内部通过Futures进行异步操作。

我正在与Akka团队负责人Roland Kuhn合著一本新书,名为《反应式设计模式》,我们在书中讨论了所有这些内容以及更多内容。绿色线程、CSP、事件循环、迭代器、响应式扩展、Actor、Futures/Promises等。预计下个月初在Manning上发布MEAP(早期访问版)。

英文:

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.

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.async currently 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.

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.

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 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.

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.

答案2

得分: 63

这里有两个问题:

  • Scala是将goroutines移植的好选择吗?

这是一个简单的问题,因为Scala是一种通用的语言,与其他许多选择“移植goroutines”的语言一样好也不差。

当然,关于Scala作为一种语言的优劣有很多观点(例如,这里是我的观点),但这些只是观点,不要让它们阻止你。由于Scala是通用的,它“几乎可以”归结为:你可以在语言X中做的任何事情,你都可以在Scala中做到。如果听起来太宽泛了...那么Java中的continuations怎么样 Scala的actors和Go的coroutines相似吗?

  • Scala actors和goroutines相似吗?

除了一些细微的差别,它们都涉及并发和消息传递。但相似之处就到此为止了。

由于Jamie的回答已经很好地概述了Scala actors,我将更多地关注Goroutines/core.async,但也会介绍一些actor模型的基础知识。

Actors帮助实现“无忧分布式”


“无忧”通常与诸如“容错性”、“弹性”、“可用性”等术语相关联。

不详细介绍actors的工作原理,简单来说,actors涉及以下两个方面:

  • 局部性:每个actor都有一个地址/引用,其他actor可以使用该地址/引用向其发送消息
  • 行为:当消息到达actor时,将应用/调用的函数

可以将其视为“交谈的进程”,每个进程都有一个引用和一个在消息到达时调用的函数。

当然,还有很多其他方面(例如,查看Erlang OTPakka文档),但以上两个方面是一个很好的起点。

有趣的地方在于actors的实现。目前有两个主要的实现,即Erlang OTP和Scala AKKA。虽然它们都旨在解决同样的问题,但也存在一些差异。让我们看看其中的一些差异:

  • 我故意不使用“引用透明”、“幂等性”等术语,因为它们只会引起混淆,所以我们只谈论不可变性[一个“无法改变的”概念]。作为一种语言,Erlang是有主见的,并且倾向于强大的不可变性,而在Scala中,很容易创建在接收到消息时更改/改变其状态的actors。虽然不建议这样做,但在Scala中,可变性就在眼前,人们确实使用它。

  • 另一个有趣的观点是Joe Armstrong提到的事实,即Scala/AKKA受到JVM的限制,而JVM并没有真正考虑“分布式”。这涉及许多因素,例如:进程隔离、每个进程与整个VM垃圾回收、类加载、进程调度等等。

上述观点的目的不是说一个比另一个更好,而是要显示actor模型作为一个概念的纯度取决于其实现。

现在来看goroutines...

Goroutines帮助按顺序推理并发


正如其他答案已经提到的,goroutines源于Communicating Sequential Processes,这是一种“描述并发系统中交互模式的形式化语言”,根据定义可以意味着几乎任何事情 Scala的actors和Go的coroutines相似吗?

我将基于core.async给出示例,因为我对它的内部了解比对Goroutines更深入。但是core.async是在Goroutines/CSP模型之后构建的,因此在概念上应该没有太多区别。

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

免费24小时停车

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

通过视觉效果更容易理解。下面是阻塞IO执行的示例:

Scala的actors和Go的coroutines相似吗?

可以看到线程大部分时间都在等待工作。下面是使用“Goroutine”/“go block”方法完成的相同工作:

Scala的actors和Go的coroutines相似吗?

在这里,两个线程完成了四个线程在阻塞方法中完成的工作,而花费的时间相同。

上述描述中的关键是:当线程没有工作时,它们被“停放”,这意味着它们的状态被“卸载”到状态机,并且实际的JVM线程可以自由地执行其他工作(来源提供了一个很好的视觉效果)。

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

Go Channel的威力

“Goroutines”/“go blocks”中的另一个重要特性是可以对通道执行的操作。例如,可以创建一个超时通道,在X毫秒后关闭。或者使用select/alt!函数,与多个通道结合使用时,它可以像在不同通道之间进行“准备好了”轮询机制。将其视为非阻塞IO中的套接字选择器。下面是使用timeout channelalt!的示例:

(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可能不是你的首选语言,但你不能否认这种并发实现看起来和感觉上是顺序的。

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

Go UI Go!

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

但它不必如此。上面来自wracer的示例实际上是用ClojureScript编写的,它编译成JavaScript。是的,它可以在具有多个线程的服务器上工作,也可以在浏览器中工作:代码可以保持不变。

Goroutines vs. core.async

再次强调一些实现差异[还有更多],以强调理论概念在实践中并不完全一对一:

  • 在Go中,通道是有类型的,在core.async中则不是:例如,在core.async中,您可以在同一个通道上放置任何类型的消息。
  • 在Go中,您可以在通道上放置可变的东西。虽然不建议这样做,但是可以。在core.async中,根据Clojure的设计,所有数据结构都是不可变的,因此通道中的数据对其自身的安全性来说更加安全。

那么结论是什么呢?


我希望上述内容能够阐明actor模型和CSP之间的差异。

并不是为了引发争论,而是为了给你另一个视角,比如Rich Hickey所说的:

我对actors并不感到热衷。它们仍然将生产者与消费者耦合在一起。是的,可以使用actors模拟或实现某些类型的队列(显然,人们经常这样做),但由于任何actor机制已经包含了一个队列,因此似乎明显队列更为基本。值得注意的是,Clojure用于并发状态的机制仍然可行,而通道则更加关注系统的流动方面。”(来源

然而,在实践中,WhatsApp是基于Erlang OTP构建的,而且似乎卖得很好。

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

“_缓冲发送不会向发送方确认,并且可能需要任意长的时间。缓冲通道和goroutines与actor模型非常接近。

真正的区别在于通道是一等公民。还有一个重要的区别:它们是间接的,就像文件描述符而不是文件名,允许以不太容易在actor模型中表达的并发样式。当然也有相反的情况;我不是在做价值判断。从理论上讲,这两种模型是等价的。”(来源

英文:

There are two questions here:

  • Is Scala a good choice to port 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".

There are of course many opinions on why Scala is better or worse as a language (e.g. here is 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的actors和Go的coroutines相似吗?

  • Are Scala actors similar to 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.

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..

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.

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:

  • 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 that concept]. 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 do use 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.

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.

Now to goroutines..

Goroutines help to reason about concurrency sequentially


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 Scala的actors和Go的coroutines相似吗?

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

The main concurrency primitive in core.async/Goroutine is a channel. Think about a channel as 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 channel and puts/takes (e.g. sends/receives) messages to/from it.

Free 24 hour Parking

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

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

Scala的actors和Go的coroutines相似吗?

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

Scala的actors和Go的coroutines相似吗?

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

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 (source for a great visual)

note: in core.async, channel can be used 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.

Power of a Go Channel

Another huge thing in "Goroutines"/"go blocks" is operations that can be performed on a channel. For example, a timeout channel can 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 channel and alt! together:

(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, or times 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 sequential this implementation of concurrency looks and feels.

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!

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.

But it does not have to be this way. The above example from wracer is 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.

Goroutines vs. 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.

So what's the verdict?


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

Not to cause a flame war, but to give you yet another perspective of let's say 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)

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

Another interesting quote is from 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.

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)

答案3

得分: 8

将我的一些评论移动到一个答案中。它变得太长了 :D(不是为了抹杀jamie和tolitius的帖子;它们都是非常有用的答案)。

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

通道也是有类型的,而邮箱则没有。在我看来,这是一件大事,对于一个基于Scala的系统来说,这相当令人震惊。我理解使用类型化消息很难实现become,但也许这表明become并不是非常符合Scala的风格。我可以这样说Akka的整体情况。它经常感觉像是自己的东西,碰巧在Scala上运行。Goroutines是Go存在的一个关键原因。

别误会我;我非常喜欢actor模型,我通常喜欢Akka,并且发现在其中工作很愉快。我也通常喜欢Go(我觉得Scala很美,而我觉得Go只是有用;但它确实非常有用)。

但是在我看来,容错性才是Akka的重点。你碰巧得到了并发性。并发是goroutines的核心。在Go中,容错性是一个单独的事情,委托给deferrecover,它们可以用来实现相当多的容错性。Akka的容错性更加正式和功能丰富,但也可能更加复杂。

总之,尽管有一些相似之处,Akka不是Go的超集,它们在功能上有显著的分歧。Akka和Go在鼓励解决问题的方式上非常不同,其中一个系统中容易的事情,在另一个系统中可能很笨拙、不切实际,或者至少不符合惯例。这就是任何系统的关键区别。

所以回到你的实际问题:我强烈建议在将Go接口引入Scala或Akka之前重新思考。确保你按照目标环境的方式来做事情。直接移植一个复杂的Go库很可能不适合这两个环境。

英文:

Moving some of my comments to an answer. It was getting too long Scala的actors和Go的coroutines相似吗? (Not to take away from jamie and tolitius's posts; they're both very useful answers.)

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 &lt;- to wait for it to finish before moving on. Akka has a less-powerful form of this with ask, but ask isn't really the Akka way 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 become is hard to implement with typed messages, but maybe that indicates that become isn'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.

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

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 defer and 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.

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.

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.

答案4

得分: 6

这些都是很好而且详尽的回答。但是为了简单地理解,这是我的观点。Goroutines是Actor的简单抽象。Actor只是Goroutines的一个更具体的用例。

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

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

然而,一个权衡是,由于Actors是一个更具体的情况,像Erlang这样的Actor实现可以更好地优化它们(在收件箱循环上进行尾递归),并且可以更容易地提供其他内置功能(多进程和多机器的Actors)。

英文:

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.

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

But as Goroutines are an abstraction, a more general design than actors, Goroutines can be used for far more tasks and designs than 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).

答案5

得分: 2

在Actor模型中,可寻址的实体是Actor,即消息的接收者。而在Go通道中,可寻址的实体是通道,即消息流动的管道。

在Go通道中,你将消息发送到通道中,可以有任意数量的接收者监听,其中一个将接收到消息。

而在Actor模型中,只有一个Actor会接收到你发送的消息,即通过Actor引用发送消息的那个Actor。

英文:

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.

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.

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

huangapple
  • 本文由 发表于 2014年3月25日 06:01:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/22621514.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定