[b]概述[/b]
我一直在找一种好的方法来解释 go 语言的[url=http://golang.org/doc/effective_go.html#concurrency]并发模型[/url]:
不要通过共享内存来通信,相反,应该通过通信来共享内存
但是没有发现一个好的解释来满足我下面的需求:
1.通过一个例子来说明最初的问题
2.提供一个共享内存的解决方案
3.提供一个通过通信的解决方案
这篇文章我就从这三个方面来做出解释。
读过这篇文章后你应该会了解通过通信来共享内存的模型,以及它和通过共享内存来通信的区别,你还将看到如何分别通过这两种模型来解决访问和修改共享资源的问题。
[b]前提[/b]
设想一下我们要访问一个银行账号:
[url=http://golang.org/ref/spec#Select_statements]select [/url]不断地从各个通道中取出消息,每个通道都跟它们所要执行的操作相一致。
重要的一点是:在 select 声明内部的一切都是相继执行的(在同一个处理程序中排队执行)。一次只有一个事件(在通道中接受或者发送)发生,这样就保证了同步访问共享资源。
领会这个有一点绕。
让我们用例子来看看 Balance() 的执行情况:
一张附属卡的流程 | 控制流程
----------------------------------------------
1. b.Balance() |
2. ch -> [acc.balances]-> ch
3. <-ch | balance = acc.account.Balance()
4. return balance <-[ch]<- balance
5 |
这两个流程都干了点什么呢?
[b]附属卡的流程[/b]
1.调用 b.Balance()
2.新建通道 ch,将 ch 通道塞入通道 acc.balances 中与控制流程通信,这样控制流程也可以通过 ch 来返回余额
3.等待 <-ch 来取得要接受的余额
4.接受余额
5.继续
[b]控制流程[/b]
1.空闲或者处理
2.通过 acc.balances 通道里面的 ch 通道来接受余额请求
3.取得真正的余额值
4.将余额值发送到 ch 通道
5.准备处理下一个请求
控制流程每次只处理一个 事件。这也就是为什么除了描述出来的这些以外,第2-4步没有别的操作执行。
[b]总结[/b]
这篇博客描述了问题以及问题的解决办法,但那时没有深入去探究不同解决办法的优缺点。
其实这篇文章的例子更适合用 mutex,因为这样代码更加清晰。
最后,请毫无顾忌的指出我的错误!