modified: eBook/14.2.md

modified:   eBook/14.4.md
This commit is contained in:
songleo
2016-01-11 11:20:14 +08:00
parent 2df6179a14
commit 9acf3a03f9
2 changed files with 10 additions and 10 deletions

View File

@@ -249,7 +249,7 @@ go sum(bigArray, ch) // bigArray puts the calculated sum on ch
sum := <- ch // wait for, and retrieve the sum sum := <- ch // wait for, and retrieve the sum
``` ```
也可以使用通道来达到同步的目的,这个很有效的用法在传统计算机中成为semaphore。或者换个方式通过通道发送信号告知处理已经完成在协程中 也可以使用通道来达到同步的目的,这个很有效的用法在传统计算机中称为信号量semaphore。或者换个方式通过通道发送信号告知处理已经完成在协程中
在其他协程运行时让 main 程序无限阻塞的通常做法是在 `main` 函数的最后放置一个{}。 在其他协程运行时让 main 程序无限阻塞的通常做法是在 `main` 函数的最后放置一个{}。
@@ -274,7 +274,7 @@ func main(){
} }
``` ```
这个信号也可以是其他的,不回结果,比如下这个协程中的 lambda 函数协程: 这个信号也可以是其他的,不回结果,比如下这个协程中的匿名函数(lambda协程:
```go ```go
ch := make(chan int) ch := make(chan int)
@@ -302,7 +302,7 @@ go doSort(s[i:])
<-done <-done
``` ```
下边的代码,用完整的信号量模式对 size 长度的 gloat64 切片进行了 N 个` doSomething()` 计算并同时完成,通道 sem 分配了相同的长度(切包含空接口类型的元素),待所有的计算都完成后,发送信号(通过放入值)。在循环中从通道 sem 不停的接收数据来等待所有的协程完成。 下边的代码,用完整的信号量模式对长度为Nfloat64 切片进行了 N 个` doSomething()` 计算并同时完成,通道 sem 分配了相同的长度(切包含空接口类型的元素),待所有的计算都完成后,发送信号(通过放入值)。在循环中从通道 sem 不停的接收数据来等待所有的协程完成。
```go ```go
type Empty interface {} type Empty interface {}
@@ -343,11 +343,11 @@ for i, v := range data {
信号量是实现互斥锁(排外锁)常见的同步机制,限制对资源的访问,解决读写问题,比如没有实现信号量的 `sync` 的 Go 包,使用带缓冲的通道可以轻松实现: 信号量是实现互斥锁(排外锁)常见的同步机制,限制对资源的访问,解决读写问题,比如没有实现信号量的 `sync` 的 Go 包,使用带缓冲的通道可以轻松实现:
- 带缓冲通道的容量和我们要同步的资源容量相同 - 带缓冲通道的容量和要同步的资源容量相同
- 通道的长度(当前存放的元素个数)当前资源被使用的数量相同 - 通道的长度(当前存放的元素个数)当前资源被使用的数量相同
- 容量减去通道的长度就是未处理的资源个数(标准信号量的整数值) - 容量减去通道的长度就是未处理的资源个数(标准信号量的整数值)
不用管通道中存放的是什么,只关注长度;因此我们创建了一个长度量为 0字节的通道 不用管通道中存放的是什么,只关注长度;因此我们创建了一个长度可变但容量为0字节的通道
```go ```go
type Empty interface {} type Empty interface {}
@@ -403,7 +403,7 @@ func (s semaphore) Signal() {
习惯用法:通道工厂模式 习惯用法:通道工厂模式
编程中常见另外一种模式如下:不将通道作为参数传递给协程,而用函数来生成一个通道并返回(工厂角色);函数内有个 lambda 函数被协程调用。 编程中常见另外一种模式如下:不将通道作为参数传递给协程,而用函数来生成一个通道并返回(工厂角色);函数内有个匿名函数被协程调用。
在 [channel_block2.go](examples/chapter_14/channel_block2.go) 加入这种模式便有了示例 14.5-[channel_idiom.go](examples/chapter_14/channel_idiom.go) 在 [channel_block2.go](examples/chapter_14/channel_block2.go) 加入这种模式便有了示例 14.5-[channel_idiom.go](examples/chapter_14/channel_idiom.go)

View File

@@ -1,6 +1,6 @@
# 14.4 使用select切换协程 # 14.4 使用select切换协程
从不同的并发执行的协程中获取值可以通过关键字`select`来完成,它和`switch`控制语句非常相似章节5.3)也被称作通信开关;它的行为像是“你准备好了吗”的轮询机制;`select`监听进入通道的数据,也可以是用通道发送值的时候。 从不同的并发执行的协程中获取值可以通过关键字`select`来完成,它和`switch`控制语句非常相似章节5.3)也被称作通信开关;它的行为像是“你准备好了吗”的轮询机制;`select`监听进入通道的数据,也可以是用通道发送值的时候。
```go ```go
select { select {
case u:= <- ch1: case u:= <- ch1:
@@ -14,7 +14,7 @@ default: // no value ready to be received
``` ```
`default`语句是可选的fallthrough行为和普通的switch相似是不允许的。在任何一个case中执行`break`或者`return`select就结束了。 `default`语句是可选的fallthrough行为和普通的switch相似是不允许的。在任何一个case中执行`break`或者`return`select就结束了。
`select`就是:选择处理列出的多个通信情况中的一个。 `select`就是:选择处理列出的多个通信情况中的一个。
* 如果都阻塞了,会等待直到其中一个可以处理 * 如果都阻塞了,会等待直到其中一个可以处理
* 如果多个可以处理,随机选择一个 * 如果多个可以处理,随机选择一个
* 如果没有通道操作可以处理并且写了`default`语句,它就会执行:`default`永远是可运行的(这就是准备好了,可以执行)。 * 如果没有通道操作可以处理并且写了`default`语句,它就会执行:`default`永远是可运行的(这就是准备好了,可以执行)。
@@ -157,7 +157,7 @@ func backend() {
另一种方式(但是不太灵活)就是(客户端)在`chRequest`上提交请求,后台协程循环这个通道,使用`switch`根据请求的行为来分别处理: 另一种方式(但是不太灵活)就是(客户端)在`chRequest`上提交请求,后台协程循环这个通道,使用`switch`根据请求的行为来分别处理:
```go ```go
func backent() { func backend() {
for req := range chRequest { for req := range chRequest {
switch req.Subjext() { switch req.Subjext() {
case A1: // Handle case ... case A1: // Handle case ...