2016-04-03 86 views
8

共享内存我不知道什么是最下边这个名言地解释:说明:不要通过共享内存进行通信;通过交流

不要通过共享内存通信;通过通信共享内存。 (R.派克)

The Go Memory Model我可以读取该:

A中的信道上发送的之前发生相应的接收从该信道完成。 (Golang Spec)

还有一个专门的golang article解释报价。关键的贡献是一个working example也由安德鲁G.

那么。有时候,太多的交谈围绕....我从内存规格报价得出,也看在工作实例如下:

后goroutine1通过通道,那么所有的修改发送(任何)到goroutine2 (在内存中的任何位置)通过goroutine1完成后,必须通过同一通道接收后才能看到goroutine2。 (Golang引理由我:)

Therfore我得出下到名言地解释:

要同步两个够程之间的内存访问,你并不需要通过送内存渠道。足够好的是从渠道接收(甚至没有)。您将看到goroutine在发送时(发送到频道)写入(任何地方)的任何更改。 (当然,假设没有其它够程被写入相同的内存。)更新(2)2017年8月26日

我有实际上是两个问题:

1)我的结论正确?

2)我的解释有帮助吗?

更新(1) 我假定无缓冲通道。让我们首先限制自己,避免以太多未知数来彻底改变自己。

请,我们还集中在两个够程通信的单信道及相关的记忆效应,而不是最佳做法的一个简单的用例 - 这超出了这个问题的范围。

为了更好地理解我的问题的范围,假设goroutines可以访问任何类型的内存结构 - 不仅仅是原始内存结构 - 它可以是一个很大的内存结构,它可以是字符串,映射,数组等等。

+0

TODO写测试 – honzajde

回答

2

从本质上讲,是的。在通道发送之前分配给变量的任何值都有资格在通道读取后被观察,因为通道操作强加了排序约束。但重要的是要记住等式的另一部分:如果你想保证这些值被观察到,你必须确保没有其他人可以在写入和读取之间写入这些变量。显然,使用锁定是可能的,但同时也是毫无意义的,因为如果您已经将锁定和跨线程内存修改组合在一起,那么您从渠道获得哪些好处?你可以像布尔一样简单地传递一些东西,作为允许独占访问全局数据的令牌,并且在内存模型保证方面(只要你的代码没有错误),它是100%正确的,它可能仅仅是一个糟糕的设计,因为你会没有充分的理由将所有事情都隐含起来并采取行动,明确地传递数据通常会变得更清晰并且不易出错。

+0

到目前为止,这解决了我的问题。谢谢。仍然在等待Rob P.说他的部分:) – honzajde

3

我不这么认为。要点不是用锁或其他并发原语来保护一个固定的存储器地址,你可以通过设计来设计程序,使得只有一个执行流被允许访问该存储器

实现这一点的简单方法是通过通道共享内存的引用。 一旦你通过频道发送你的参考忘记它。通过这种方式,只有使用该通道的例程才能访问它。

+0

是的,其要点是关于完全的东西 - 正如你在第二段中所描述的那样。但是,如果我错了,我错了吗? – honzajde

10

这个着名的引用可能有点混乱,如果采取太litteralterally。让我们把它分解到它的多种碱性成分,并正确地定义他们:

Don't communicate by sharing memory; share memory by communicating 
     ---- 1 ---- ------ 2 ----- ---- 3 ----- ----- 4 ----- 
  1. 这意味着,不同的执行线程将其他线程的状态的变化通过读取内存将被某处修改通知其他。 这是一个完美的例子(尽管对于进程而不是线程)是POSIX共享内存API:http://man7.org/linux/man-pages/man7/shm_overview.7.html。 这种技术需要适当的同步,因为数据竞赛可以很容易地发生。
  2. 这意味着确实存在一部分物理或虚拟内存,可以从多个线程中修改,也可以从这些线程中读取。没有明确的所有权概念,内存空间同样可以从所有线程访问。
  3. 这是完全不同的。在Go中,像上面一样共享内存是可能的,并且数据竞速可以非常容易地发生,所以这实际上意味着修改goroutine中的变量,不管是像int这样的简单值,还是像地图这样的复杂数据结构,并通过通道机制将值或指针指向不同的goroutine发送给所有者。理想情况下,没有共享空间,每个goroutine只能看到它拥有的部分内存。
  4. 这里的通信意味着只有一个队列的通道允许一个goroutine从中读取,因此被通知新内存部分的所有权,而另一个通道发送并接受丢失所有权。这是一个简单的消息传递模式。

总之,什么报价方式可以这样概括:

不要使用共享内存和复杂,容易出错的同步原语overengineer线程间通信,而是使用消息在goroutines(绿色线程)之间传递,所以变量和数据可以在这些消息之间顺序使用。

在这里使用单词序列是值得注意的,因为它描述了灵感来自goroutines和渠道概念的哲学:Communicating Sequential Processes

+0

感谢您的贡献@SirDarius。到目前为止,我问的这个问题让我很开心:)我希望对其他人也是如此。但是,您对我的问题的答案是1)否2)否? – honzajde

+0

我会说,是的,是的,尽管我不确定结论的语句对于Go开发人员来说听起来是“惯用的”,如果你明白我的意思。缺失的东西基本上是所有权传递的概念。 – SirDarius

+0

答案中的这部分内容真的很具误导性:“......通过通过渠道机制将值或指针发送给不同的goroutine来放弃所有权” - 没有所有权的概念,事实上假设因此如果发送goroutine再次修改数据会导致竞争状态。 – honzajde

1

1)我的结论是否正确?

我这么认为,如果这意味着我希望它有。规范中使用“偶然”术语的语言的原因在于,它为表达想法提供了明确的沟通形式。

您的描述的问题是,您实际上没有明确定义您的突发事件订单。我认为,尽管你暗示着一个命令。如果你的意思是“在goroutine a之前发生的运行a在特定的同步点上运行,在goroutine b也观察到同样的同步点之后goroutine b可以看到” - 即使在这里,“同步点”定义不明确 - 尽管我希望你能理解它。正如规范所做的那样,这种观点可以在偶然事件中进行定义。

2)我的解释有帮助吗?

也许,不熟悉这个主题的人或者正在努力理解描述的偶然风格风格的人可能会发现你的描述更易于解释。然而,在你的描述中有一些限制和潜在的实际问题,如下所示:

  • 你还没有严格定义你所说的“发送”是同步点。如果你的意思是发送一个无缓冲的频道,那么是的,这将创建一个共享同步点,通过规范引入严格的发生顺序。
  • 虽然假设上述内容属实,但您已经描述了一个同步点,但这只能解决原始建议的一个方面。最初的建议包括“所有权转让”的概念,并且与创建同步点或偶发事件的关系较少,更多涉及长期维护依赖潜在共享内存的代码。这个概念是,不是保留对两个地方某段内存的访问,而是创建单独的共享同步点(如互斥锁),可以将对象的唯一引用从一个所有者传递给另一个所有者。以这种方式设计软件可防止同步点之外的意外修改,这在软件中经常可以观察到,这些软件通过精确使用互斥和广泛使用共享内存。

互斥或“显式同步点”是完全相同的建议的相反 - 它们的存储器中的共享片是,用于进行通信的同步点“通过共享存储器进行通信”,反之,即使它们具有互斥在底层深处,通道是一种将对象的所有权(发送值)从一个goroutine(发送者)传递给另一个goroutine(接收者)的抽象机制。重点在于,忽略通道是如何实现的,用户通过将其从一个所有者(例程a)传递给另一个(例程b)来共享内存(值)。如果您使用通道发送无关数据来创建同步点,则实际上将它用作互斥量,这更接近通过共享内存进行通信(专注于通道),而不是通过通信进行共享(专注于价值)。

我希望这会有所帮助。

+0

感谢您指出缓冲的频道!我已经更新了我的问题,因此很明显,我首先假定了无缓冲的渠道。 – honzajde

3

这里有两句话;为了更全面的理解,必须首先单独查看这些信息,然后将它们聚合在一起,所以: Don't communicate by sharing memory;意思是,不同的线程不应该通过遵守严格且易于出错的内存可见性和同步策略(如内存障碍等)来相互通信。它可以完成,但它可能很快会变得复杂并且数据竞争非常麻烦)。因此,避免遵守手动,程序化的可见性构造主要通过像Java这样的编程语言进行适当的同步。

share memory by communicating.表示如果一个线程对内存区域进行了任何更改(写入),它应该将相同的内存区域(内存区域)传递给对同一内存区域感兴趣的线程;注意这已经将内存范围限制为只有两个线程。

现在阅读上述两段,结合golang内存模型,它说,A send on a channel happens before the corresponding receive from that channel completes.发生之前的关系证实,通过第一个goroutine的写入将会看到第二个goroutine接收到另一端的内存引用这个频道!

3

让我简单点,在这里。

不要通过共享内存进行通信。

这就好比你在使用线程进行通信时,例如你必须使用变量或互斥锁来锁定内存,以防止某人在通信完成之前读取和写入内存。通过通信

在Go例程值在信道,而不是阻断存储器移动

共享存储器,发送机通知接收机,用于从该信道接收,因此它通过与接收器通信从得到共享存储器渠道。