Fix 14.5, 14.6, 15.1 (#283)

* Update 07.3.md

* Update 07.3.md

* Update 07.6.md

* fix few problems

* Update 10.6 and 10.8

* Update 11.6 and 11.7

* fix some problems before Chap13

* add a dot

* Update 13.9

* little improve

* Thoughts about time.After

* Thoughts about time.After

* Fix 14.6,15.1
This commit is contained in:
王耀
2016-11-20 11:22:57 +08:00
committed by 无闻
parent 6d6c46c6c8
commit f2a3e873fe
6 changed files with 28 additions and 13 deletions

View File

@@ -137,7 +137,7 @@ select {
第二种形式:取消耗时很长的同步调用
也可以使用 `time.After()` 函数替换 `timeout-channel`。可以在 `select`使用以发送信号超时或停止协程的执行。以下代码,在 `timeoutNs` 纳秒后执行 `select``timeout` 分支时,`client.Call` 不会给通道 `ch` 返回值:
也可以使用 `time.After()` 函数替换 `timeout-channel`。可以在 `select`通过 `time.After()` 发送的超时信号来停止协程的执行。以下代码,在 `timeoutNs` 纳秒后执行 `select``timeout` 分支后,执行`client.Call` 的协程也随之结束,不会给通道 `ch` 返回值:
```go
ch := make(chan error, 1)
@@ -151,7 +151,22 @@ case <-time.After(timeoutNs):
}
```
注意缓冲大小设置为 1 是必要的,可以避免协程死锁以及确保超时的通道可以被垃圾回收。
注意缓冲大小设置为 1 是必要的,可以避免协程死锁以及确保超时的通道可以被垃圾回收。此外,需要注意在有多个 `case` 符合条件时, `select``case` 的选择是伪随机的,如果上面的代码稍作修改如下,则 `select` 语句可能不会在定时器超时信号到来时立刻选中 `time.After(timeoutNs)` 对应的 `case`,因此协程可能不会严格按照定时器设置的时间结束。
```go
ch := make(chan int, 1)
go func() { for { ch <- 1 } } ()
L:
for {
select {
case <-ch:
// do something
case <-time.After(timeoutNs):
// call timed out
break L
}
}
```
第三种形式:假设程序从多个复制的数据库同时读取。只需要一个答案,需要接收首先到达的答案,`Query` 函数获取数据库的连接切片并请求。并行请求每一个数据库并返回收到的第一个响应:

View File

@@ -21,7 +21,7 @@ func safelyDo(work *Work) {
上边的代码,如果 `do(work)` 发生 panic错误会被记录且协程会退出并释放而其他协程不受影响。
因为 `recover` 总是返回 `nil`,除非直接在 `defer` 修饰的函数中调用,`defer` 修饰的代码可以调用那些自身可以使用 `panic``recover` 避免失败的库例程(库函数)。举例,`safelyDo()``deffer` 修饰的函数可能在调用 `recover` 之前就调用了一个 `logging` 函数,`panicking` 状态不会影响 `logging` 代码的运行。因为加入了恢复模式,函数 `do`(以及它调用的任何东西)可以通过调用 `panic` 来摆脱不好的情况。但是恢复是在 `panicking` 的协程内部的:不能被另外一个协程恢复。
因为 `recover` 总是返回 `nil`,除非直接在 `defer` 修饰的函数中调用,`defer` 修饰的代码可以调用那些自身可以使用 `panic``recover` 避免失败的库例程(库函数)。举例,`safelyDo()``defer` 修饰的函数可能在调用 `recover` 之前就调用了一个 `logging` 函数,`panicking` 状态不会影响 `logging` 代码的运行。因为加入了恢复模式,函数 `do`(以及它调用的任何东西)可以通过调用 `panic` 来摆脱不好的情况。但是恢复是在 `panicking` 的协程内部的:不能被另外一个协程恢复。
## 链接

View File

@@ -35,18 +35,18 @@ func main() {
func doServerStuff(conn net.Conn) {
for {
buf := make([]byte, 512)
_, err := conn.Read(buf)
len, err := conn.Read(buf)
if err != nil {
fmt.Println("Error reading", err.Error())
return //终止程序
}
fmt.Printf("Received data: %v", string(buf))
fmt.Printf("Received data: %v", string(buf[:len]))
}
}
```
我们在`main()`创建了一个`net.Listener`的变量他是一个服务器的基本函数用来监听和接收来自客户端的请求来自localhost即IP地址为127.0.0.1端口为50000基于TCP协议。这个`Listen()`函数可以返回一个`error`类型的错误变量。用一个无限for循环的`listener.Accept()`来等待客户端的请求。客户端的请求将产生一个`net.Conn`类型的连接变量。然后一个独立的携程使用这个连接执行`doServerStuff()`开始使用一个512字节的缓冲`data`来读取客户端发送来的数据并且把它们打印到服务器的终端;当客户端发送的所有数据都被读取完成时,携程就结束了。这段程序会为每一个客户端连接创建一个独立的携程。必须先运行服务器代码,再运行客户端代码。
我们在`main()`创建了一个`net.Listener`的变量他是一个服务器的基本函数用来监听和接收来自客户端的请求来自localhost即IP地址为127.0.0.1端口为50000基于TCP协议。这个`Listen()`函数可以返回一个`error`类型的错误变量。用一个无限for循环的`listener.Accept()`来等待客户端的请求。客户端的请求将产生一个`net.Conn`类型的连接变量。然后一个独立的携程使用这个连接执行`doServerStuff()`开始使用一个512字节的缓冲`data`来读取客户端发送来的数据并且把它们打印到服务器的终端`len`获取客户端发送的数据字节数;当客户端发送的所有数据都被读取完成时,携程就结束了。这段程序会为每一个客户端连接创建一个独立的携程。必须先运行服务器代码,再运行客户端代码。
客户端代码写在另外一个文件client.go中
@@ -106,7 +106,7 @@ func main() {
然后开启2个或者3个独立的控制台窗口然后分别输入client回车启动客户端程序
以下是服务器的输出在移除掉512字节的字符串中内容为空的区域后
以下是服务器的输出:
```
Starting the Server ...
Received data: IVO says: Hi Server, what's up ?
@@ -229,7 +229,7 @@ func main() {
func initServer(hostAndPort string) *net.TCPListener {
serverAddr, err := net.ResolveTCPAddr("tcp", hostAndPort)
checkError(err, "Resolving address:port failed: '"+hostAndPort+"'")
listener, err := net.ListenTCP("tcp", serverAddr)
listener, err := net.Listen("tcp", serverAddr)
checkError(err, "ListenTCP: ")
println("Listening to: ", listener.Addr().String())
return listener

View File

@@ -27,11 +27,11 @@ func main() {
func doServerStuff(conn net.Conn) {
for {
buf := make([]byte, 512)
_, err := conn.Read(buf)
len, err := conn.Read(buf)
if err != nil {
fmt.Println("Error reading", err.Error())
return //终止程序
}
fmt.Printf("Received data: %v", string(buf))
fmt.Printf("Received data: %v", string(buf[:len]))
}
}

View File

@@ -4,8 +4,8 @@ package main
import (
"flag"
"fmt"
"os"
"net"
"os"
)
const maxRead = 25
@@ -27,7 +27,7 @@ func main() {
func initServer(hostAndPort string) *net.TCPListener {
serverAddr, err := net.ResolveTCPAddr("tcp", hostAndPort)
checkError(err, "Resolving address:port failed: '"+hostAndPort+"'")
listener, err := net.ListenTCP("tcp", serverAddr)
listener, err := net.Listen("tcp", serverAddr)
checkError(err, "ListenTCP: ")
println("Listening to: ", listener.Addr().String())
return listener

View File

@@ -26,7 +26,7 @@ func main() {
func initServer(hostAndPort string) *net.TCPListener {
serverAddr, err := net.ResolveTCPAddr("tcp", hostAndPort)
checkError(err, "Resolving address:port failed: '"+hostAndPort+"'")
listener, err := net.ListenTCP("tcp", serverAddr)
listener, err := net.Listen("tcp", serverAddr)
checkError(err, "ListenTCP: ")
println("Listening to: ", listener.Addr().String())
return listener