更新链接、修正全角括号 (#281)

* 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
This commit is contained in:
王耀
2016-09-04 18:04:40 +08:00
committed by 无闻
parent f27a8d84bf
commit 86b9d6f7ef
3 changed files with 11 additions and 11 deletions

View File

@@ -6,7 +6,7 @@
```sh ```sh
#!/bin/sh #!/bin/sh
/usr/bin/time -f %Uu %Ss %er %MkB %C$@ /usr/bin/time -f '%Uu %Ss %er %MkB %C' "$@"
``` ```
在 Unix 命令行中像这样使用 ```xtime goprogexec```,这里的 progexec 是一个 Go 可执行程序这句命令行输出类似56.63u 0.26s 56.92r 1642640kB progexec分别对应用户时间系统时间实际时间和最大内存占用。 在 Unix 命令行中像这样使用 ```xtime goprogexec```,这里的 progexec 是一个 Go 可执行程序这句命令行输出类似56.63u 0.26s 56.92r 1642640kB progexec分别对应用户时间系统时间实际时间和最大内存占用。
@@ -24,11 +24,11 @@
你可以在单机程序 progexec 中引入 runtime/pprof 包;这个包以 pprof 可视化工具需要的格式写入运行时报告数据。对于 CPU 性能分析来说你需要添加一些代码: 你可以在单机程序 progexec 中引入 runtime/pprof 包;这个包以 pprof 可视化工具需要的格式写入运行时报告数据。对于 CPU 性能分析来说你需要添加一些代码:
```go ```go
var cpuprofile = flag.String(cpuprofile, “”, write cpu profile to file) var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
func main() { func main() {
flag.Parse() flag.Parse()
if *cpuprofile != “” { if *cpuprofile != "" {
f, err := os.Create(*cpuprofile) f, err := os.Create(*cpuprofile)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@@ -45,7 +45,7 @@ func main() {
然后可以像这样用 gopprof 工具:```gopprof progexec progexec.prof``` 然后可以像这样用 gopprof 工具:```gopprof progexec progexec.prof```
gopprof 程序是 Google pprofC++ 分析器的一个轻微变种;关于此工具更多的信息,参见[http://code.google.com/p/google-perftools/](http://code.google.com/p/google-perftools/)。 gopprof 程序是 Google pprofC++ 分析器的一个轻微变种;关于此工具更多的信息,参见[https://github.com/gperftools/gperftools](https://github.com/gperftools/gperftools)。
如果开启了 CPU 性能分析Go 程序会以大约每秒 100 次的频率阻塞,并记录当前执行的 goroutine 栈上的程序计数器样本。 如果开启了 CPU 性能分析Go 程序会以大约每秒 100 次的频率阻塞,并记录当前执行的 goroutine 栈上的程序计数器样本。
@@ -78,11 +78,11 @@ Total: 3099 samples
为了做到这一点必须在合适的地方添加下面的代码: 为了做到这一点必须在合适的地方添加下面的代码:
```go ```go
var memprofile = flag.String(memprofile, “”, write memory profile to this file) var memprofile = flag.String("memprofile", "", "write memory profile to this file")
... ...
CallToFunctionWhichAllocatesLotsOfMemory() CallToFunctionWhichAllocatesLotsOfMemory()
if *memprofile != “” { if *memprofile != "" {
f, err := os.Create(*memprofile) f, err := os.Create(*memprofile)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@@ -117,7 +117,7 @@ gopprof --inuse_objects progexec progexec.mprof
对于 web 应用来说,有标准的 HTTP 接口可以分析数据。在 HTTP 服务中添加 对于 web 应用来说,有标准的 HTTP 接口可以分析数据。在 HTTP 服务中添加
```go ```go
import _ http/pprof import _ "http/pprof"
``` ```
会为 /debug/pprof/ 下的一些 URL 安装处理器。然后你可以用一个唯一的参数——你服务中的分析数据的 URL 来执行 gopprof 命令——它会下载并执行在线分析。 会为 /debug/pprof/ 下的一些 URL 安装处理器。然后你可以用一个唯一的参数——你服务中的分析数据的 URL 来执行 gopprof 命令——它会下载并执行在线分析。

View File

@@ -10,13 +10,13 @@
**不要使用全局变量或者共享内存,它们会给你的代码在并发运算的时候带来危险。** **不要使用全局变量或者共享内存,它们会给你的代码在并发运算的时候带来危险。**
解决之道在于同步不同的线程,对数据加锁,这样同时就只有一个线程可以变更数据。在 Go 的标准库 `sync` 中有一些工具用来在低级别的代码中实现加锁;我们在第 [9.3](9.3.md) 节中讨论过这个问题。不过过去的软件开发经验告诉我们这会带来更高的复杂度,更容易使代码出错以及更低的性能,所以这个经典的方法明显不再适合现代多核/多处理器编程:`thread-per-connection` 模型不够有效。 解决之道在于同步不同的线程,对数据加锁,这样同时就只有一个线程可以变更数据。在 Go 的标准库 `sync` 中有一些工具用来在低级别的代码中实现加锁;我们在第 [9.3](09.3.md) 节中讨论过这个问题。不过过去的软件开发经验告诉我们这会带来更高的复杂度,更容易使代码出错以及更低的性能,所以这个经典的方法明显不再适合现代多核/多处理器编程:`thread-per-connection` 模型不够有效。
Go 更倾向于其他的方式,在诸多比较合适的范式中,有个被称作 `Communicating Sequential Processes顺序通信处理`CSP, C. Hoare 发明的)还有一个叫做 `message passing-model消息传递`(已经运用在了其他语言中,比如 Erlang Go 更倾向于其他的方式,在诸多比较合适的范式中,有个被称作 `Communicating Sequential Processes顺序通信处理`CSP, C. Hoare 发明的)还有一个叫做 `message passing-model消息传递`(已经运用在了其他语言中,比如 Erlang
在 Go 中,应用程序并发处理的部分被称作 `goroutines协程`,它可以进行更有效的并发运算。在协程和操作系统线程之间并无一对一的关系:协程是根据一个或多个线程的可用性,映射(多路复用,执行于)在他们之上的;协程调度器在 Go 运行时很好的完成了这个工作。 在 Go 中,应用程序并发处理的部分被称作 `goroutines协程`,它可以进行更有效的并发运算。在协程和操作系统线程之间并无一对一的关系:协程是根据一个或多个线程的可用性,映射(多路复用,执行于)在他们之上的;协程调度器在 Go 运行时很好的完成了这个工作。
协程工作在相同的地址空间中,所以共享内存的方式一定是同步的;这个可以使用 `sync` 包来实现(参见第 [9.3](9.3.md) 节不过我们很不鼓励这样做Go 使用 `channels` 来同步协程(可以参见第 [14.2](14.2.md) 节等章节) 协程工作在相同的地址空间中,所以共享内存的方式一定是同步的;这个可以使用 `sync` 包来实现(参见第 [9.3](09.3.md) 节不过我们很不鼓励这样做Go 使用 `channels` 来同步协程(可以参见第 [14.2](14.2.md) 节等章节)
当系统调用(比如等待 I/O阻塞协程时其他协程会继续在其他线程上工作。协程的设计隐藏了许多线程创建和管理方面的复杂工作。 当系统调用(比如等待 I/O阻塞协程时其他协程会继续在其他线程上工作。协程的设计隐藏了许多线程创建和管理方面的复杂工作。

View File

@@ -326,7 +326,7 @@ for i := 0; i < N; i++ { <-sem }
## 14.2.8 实现并行的 for 循环 ## 14.2.8 实现并行的 for 循环
在上一部分章节 [14.2.7](14.2.7.md) 的代码片段中for 循环的每一个迭代是并行完成的: 在上一部分章节 [14.2.7](14.2.md#1427-信号量模式) 的代码片段中for 循环的每一个迭代是并行完成的:
```go ```go
for i, v := range data { for i, v := range data {
@@ -486,7 +486,7 @@ func suck(ch chan int) {
习惯用法:通道迭代模式 习惯用法:通道迭代模式
这个模式用到了前边示例 [14.6](exercises/chapter_14/producer_consumer.go) 的模式,通常,需要从包含了地址索引字段 items 的容器给通道填入元素。为容器的类型定义一个方法 `Iter()`,返回一个只读的通道(参见第 [14.2.8](14.2.8.md) 节items如下 这个模式用到了后边14.6章示例 [producer_consumer.go](exercises/chapter_14/producer_consumer.go) 的生产者-消费者模式,通常,需要从包含了地址索引字段 items 的容器给通道填入元素。为容器的类型定义一个方法 `Iter()`,返回一个只读的通道(参见第 [14.2.8](14.2.md#1428-实现并行的-for-循环) 节items如下
```go ```go
func (c *container) Iter () <- chan items { func (c *container) Iter () <- chan items {