From 91b920bab3de45f3dbb8d9f37b51942236d1a5ae Mon Sep 17 00:00:00 2001 From: apple <2571583272@qq.com> Date: Fri, 25 May 2018 17:50:47 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=94=99=E5=AD=97?= =?UTF-8?q?=E5=92=8C=E6=8B=BC=E5=86=99=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appendix/appendix-a-trap.md | 2 +- ch1-basic/ch1-06-goroutine.md | 2 +- ch3-asm/ch3-01-basic.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/appendix/appendix-a-trap.md b/appendix/appendix-a-trap.md index 65150e6..42970ee 100644 --- a/appendix/appendix-a-trap.md +++ b/appendix/appendix-a-trap.md @@ -389,7 +389,7 @@ func main() { 上面的程序中后台Goroutine向管道输入自然数序列,main函数中输出序列。但是当break跳出for循环的时候,后台Goroutine就处于无法被回收的状态了。 -我们可以通过contxt包来避免做个问题: +我们可以通过context包来避免做个问题: ```go diff --git a/ch1-basic/ch1-06-goroutine.md b/ch1-basic/ch1-06-goroutine.md index c11ed59..c9c5b53 100644 --- a/ch1-basic/ch1-06-goroutine.md +++ b/ch1-basic/ch1-06-goroutine.md @@ -889,7 +889,7 @@ func main() { 当并发体超时或`main`主动停止工作者Goroutine时,每个工作者都可以安全退出。 -Go语言是带内存自动回收的特性,因此内存一般不会泄漏。在前面素数筛的例子中,`GenerateNatural`和`PrimeFilter`函数内部都启动了新的Goroutine,当`main`函数不再使用管道时后台Goroutine有泄漏的风险。我们可以通过`contxt`包来避免做个问题,下面是改进的素数筛实现: +Go语言是带内存自动回收的特性,因此内存一般不会泄漏。在前面素数筛的例子中,`GenerateNatural`和`PrimeFilter`函数内部都启动了新的Goroutine,当`main`函数不再使用管道时后台Goroutine有泄漏的风险。我们可以通过`context`包来避免做个问题,下面是改进的素数筛实现: ```go // 返回生成自然数序列的管道: 2, 3, 4, ... diff --git a/ch3-asm/ch3-01-basic.md b/ch3-asm/ch3-01-basic.md index 74d6fc6..268ca17 100644 --- a/ch3-asm/ch3-01-basic.md +++ b/ch3-asm/ch3-01-basic.md @@ -126,7 +126,7 @@ go.string."gopher" SRODATA dupok size=6 rel 0+8 t=1 go.string."gopher"+0 ``` -输出中出现了一个新的符号go.string."gopher",根据其长度和内容分析可以猜测是对应底层的"gopher"字符串数据。因为Go语言的字符串并不是值类型,Go字符串只是一中只读的引用类型。假设多个代码中出现了相同的"gopher"字符串时,程序链接后其实都是引用的同一个符号go.string."gopher"。因此,该符号有一个SRODATA标志表示这个数据在只读内存段,dupok表示出现多个相同符号时只保留一个就可以了。 +输出中出现了一个新的符号go.string."gopher",根据其长度和内容分析可以猜测是对应底层的"gopher"字符串数据。因为Go语言的字符串并不是值类型,Go字符串只是一种只读的引用类型。假设多个代码中出现了相同的"gopher"字符串时,程序链接后其实都是引用的同一个符号go.string."gopher"。因此,该符号有一个SRODATA标志表示这个数据在只读内存段,dupok表示出现多个相同符号时只保留一个就可以了。 而真正的Go字符串变量Name对应的大小却只有16个字节了。其实Name变量并没有直接对应“gopher”字符串,而是对应reflect.StringHeader结构体: @@ -252,7 +252,7 @@ Go语言函数在函数调用时,完全通过栈传递调用参数和返回值 ## 特殊字符 -Go语言函数或方法符号在编译为目标文件后,目标文件中的每个符号均包含对应包的觉得导入路径。因此目标文件的符号可能非常复杂,比如“path/to/pkg.(*SomeType).SomeMethod”或“go.string."abc"”。目标文件的符号名中不仅仅包含普通的字母,还可能包含诸多特殊字符。而Go语言的汇编器是从plan9移植过来的二把刀,并不能处理这些特殊的字符,导致了用Go汇编语言手工实现Go诸多特性时遇到种种限制。 +Go语言函数或方法符号在编译为目标文件后,目标文件中的每个符号均包含对应包的绝对导入路径。因此目标文件的符号可能非常复杂,比如“path/to/pkg.(*SomeType).SomeMethod”或“go.string."abc"”。目标文件的符号名中不仅仅包含普通的字母,还可能包含诸多特殊字符。而Go语言的汇编器是从plan9移植过来的二把刀,并不能处理这些特殊的字符,导致了用Go汇编语言手工实现Go诸多特性时遇到种种限制。 Go汇编语言同样遵循Go语言少即是多的哲学,它只保留了最基本的特性:定义变量和全局函数。同时为了简化Go汇编器的词法扫描程序的实现,特别引入了Unicode中的中点`·`和大写的除法`/`,对应的Unicode码点为`U+00B7`和`U+2215`。汇编器编译后,中点`·`会被替换为ASCII中的点“.”,大写点除法会被替换为ASCII码中的除法“/”,比如`math/rand·Int`会被替换为`math/rand.Int`。这样可以将点和浮点数中的小数点、大写的除法和表达式中的除法符号分开,可以简化汇编程序此法分析部分的实现。 From d8b669949ddd03d233f2daac5118cf1c5bd91724 Mon Sep 17 00:00:00 2001 From: apple <2571583272@qq.com> Date: Fri, 25 May 2018 19:07:41 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=9B=B4=E6=AD=A3=E9=94=99=E7=9A=84?= =?UTF-8?q?=E5=AD=97=E8=AF=8D=EF=BC=8C=E5=88=A0=E5=8E=BB=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E5=AD=97=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- appendix/appendix-a-trap.md | 2 +- ch1-basic/ch1-01-genesis.md | 2 +- ch1-basic/ch1-04-func-method-interface.md | 2 +- ch1-basic/ch1-06-goroutine.md | 4 ++-- ch1-basic/ch1-07-error-and-panic.md | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/appendix/appendix-a-trap.md b/appendix/appendix-a-trap.md index 42970ee..d61e9e6 100644 --- a/appendix/appendix-a-trap.md +++ b/appendix/appendix-a-trap.md @@ -389,7 +389,7 @@ func main() { 上面的程序中后台Goroutine向管道输入自然数序列,main函数中输出序列。但是当break跳出for循环的时候,后台Goroutine就处于无法被回收的状态了。 -我们可以通过context包来避免做个问题: +我们可以通过context包来避免这个问题: ```go diff --git a/ch1-basic/ch1-01-genesis.md b/ch1-basic/ch1-01-genesis.md index d8a7685..0722888 100644 --- a/ch1-basic/ch1-01-genesis.md +++ b/ch1-basic/ch1-01-genesis.md @@ -14,7 +14,7 @@ Go语言很多时候被描述为“类C语言”,或者是“21世纪的C语 最后是基因图谱的右边一支,这是对C语言的致敬。Go语言是对C语言最彻底的一次扬弃,不仅仅是语法和C语言有着很多差异,最重要的是舍弃了C语言中灵活但是危险的指针运算。而且,Go语言还重新设计了C语言中部分不太合理运算符的优先级,并在很多细微的地方都做了必要的打磨和改变。当然,C语言中少即是多、简单直接的暴力编程哲学则被Go语言更彻底地发扬光大了(Go语言居然只有25个关键字,sepc语言规范还不到50页))。 -Go语言的其它的一些特性零散地来自于其他一些编程语言;比如iota语法是从APL语言借鉴,词法作用域与嵌套函数等特性来自于Scheme语言(和其他很多编程语言)。Go语言中也有很多自己发明创新的设计。比如Go语言的切片为轻量级动态数组提供了有效的随机存取的性能,这可能会让人联想到链表的底层的共享机制。还有Go语言新发明的defer语句(Ken发明)也是神来之笔。 +Go语言其它的一些特性零散地来自于其他一些编程语言;比如iota语法是从APL语言借鉴,词法作用域与嵌套函数等特性来自于Scheme语言(和其他很多编程语言)。Go语言中也有很多自己发明创新的设计。比如Go语言的切片为轻量级动态数组提供了有效的随机存取的性能,这可能会让人联想到链表的底层的共享机制。还有Go语言新发明的defer语句(Ken发明)也是神来之笔。 ## 来自贝尔实验室特有基因 diff --git a/ch1-basic/ch1-04-func-method-interface.md b/ch1-basic/ch1-04-func-method-interface.md index 3c0f084..4c1b7ac 100644 --- a/ch1-basic/ch1-04-func-method-interface.md +++ b/ch1-basic/ch1-04-func-method-interface.md @@ -106,7 +106,7 @@ func main() { func main() { for i := 0; i < 3; i++ { - // 通过函数函数传入i + // 通过函数传入i // defer 语句会马上对调用参数求值 defer func(i int){ println(i) } (i) } diff --git a/ch1-basic/ch1-06-goroutine.md b/ch1-basic/ch1-06-goroutine.md index c9c5b53..33cff93 100644 --- a/ch1-basic/ch1-06-goroutine.md +++ b/ch1-basic/ch1-06-goroutine.md @@ -2,7 +2,7 @@ Go语言最吸引人的地方是它内建的并发支持。Go语言并发体系的理论是C.A.R Hoare在1978年提出的CSP(Communicating Sequential Process,通讯顺序进程)。CSP有着精确的数学模型,并实际应用在了Hoare实际参与设计的T9000通用计算机上。从NewSqueak、Alef、Limbo到现在的Go语言,对于对CSP有着20多年实战经验的Rob Pike来说,他更关注的是将CSP应用在通用编程语言上的潜力。作为Go并发编程核心的CSP理论的核心概念只有一个:同步通信。关于同步通信的话题我们在前面一节已经讲过,本节我们将简单介绍下Go语言中常见的并发模式。 -首先要明确一个概念:并发不是并行。并发更关注的是程序的设计层面,并发的程序完全是可以顺序执行的,只有在真正的多核CPU上才可能真正地同时运行。并行更关注的是程序的运行层面,并行一般是简单的大量重复,例如GPU中对图像处理都会有大量的并行运算。Go语言从一开始设计,就围绕着如何能在编程语言的层级,为更好的编写并发程序设计一个简洁安全高效的抽象模型,让程序员专注于分解问题和组合方案,而且不用被被线程管理和信号互斥这些繁琐的操作分散精力。 +首先要明确一个概念:并发不是并行。并发更关注的是程序的设计层面,并发的程序完全是可以顺序执行的,只有在真正的多核CPU上才可能真正地同时运行。并行更关注的是程序的运行层面,并行一般是简单的大量重复,例如GPU中对图像处理都会有大量的并行运算。Go语言从一开始设计,就围绕着如何能在编程语言的层级,为更好的编写并发程序设计一个简洁安全高效的抽象模型,让程序员专注于分解问题和组合方案,而且不用被线程管理和信号互斥这些繁琐的操作分散精力。 在并发编程中,对共享资源的正确访问需要精确的控制,在目前的绝大多数语言中,都是通过加锁等线程同步方案来解决这一困难问题,而Go语言却另辟蹊径,它将共享的值通过信道传递(实际上多个独立执行的线程很少主动共享资源)。在任意给定的时刻,最好只有一个Goroutine能够拥有该资源。数据竞争从设计层面上就被杜绝了。为了提倡这种思考方式,Go语言将其并发编程哲学化为一句口号: @@ -651,7 +651,7 @@ func main() { 对于生产者、消费者并发模型,我们当然可以通过降低生产者的产能来避免资源的浪费。但在很多场景中,生产者才是核心对象,它们生产出各种问题或任务单据,这时候产出的问题是必须要解决的、任务单据也是必须要完成的。在现实生活中,制造各种生活垃圾的海量人类其实就是垃圾生产者,而清理生活垃圾的少量的清洁工就是垃圾消费者。在网络服务中,提交POST数据的海量用户则变成了生产者,Web后台服务则对应POST数据的消费者。海量生产者的问题也就变成了:如何构造一个能够处理海量请求的Web服务(假设每分钟百万级请求)。 -在Web服务中,用户提交的每个POST请求可以看作是一个Job任务,而服务器是通过后台的Worker工作者来消费这些Job任务。当面向海量的Job处理时,我们一般可以通过构造一个Worker工作者池来提高Job的处理效率;通过通过一个带缓存的Job管道来接收新的任务请求,避免任务请求功能无法响应;Job请求接收管道和Worker工作者池通过分发系统来衔接。 +在Web服务中,用户提交的每个POST请求可以看作是一个Job任务,而服务器是通过后台的Worker工作者来消费这些Job任务。当面向海量的Job处理时,我们一般可以通过构造一个Worker工作者池来提高Job的处理效率;通过一个带缓存的Job管道来接收新的任务请求,避免任务请求功能无法响应;Job请求接收管道和Worker工作者池通过分发系统来衔接。 我们可以用管道来模拟工作者池:当需要处理一个任务时,先从工作者池取一个工作者,处理完任务之后将工作者返回给工作者池。`WorkerPool`对应工作者池,`Worker`对应工作者。 diff --git a/ch1-basic/ch1-07-error-and-panic.md b/ch1-basic/ch1-07-error-and-panic.md index c9b3826..686f49e 100644 --- a/ch1-basic/ch1-07-error-and-panic.md +++ b/ch1-basic/ch1-07-error-and-panic.md @@ -103,7 +103,7 @@ func ParseJSON(input string) (s *Syntax, err error) { } ``` -在标准库中的`json`包,在内部递归解析JSON数据的时候如果遇到错误,会通过抛出异常的方式来快速跳出深度嵌套的函数调用,然后由最外以及的接口通过`recover`捕获`panic`,然后返回相应的错误信息。 +在标准库中的`json`包,在内部递归解析JSON数据的时候如果遇到错误,会通过抛出异常的方式来快速跳出深度嵌套的函数调用,然后由最外一级的接口通过`recover`捕获`panic`,然后返回相应的错误信息。 Go语言库的实现习惯: 即使在包内部使用了`panic`,但是在导出函数时会被转化为明确的错误值。 @@ -141,7 +141,7 @@ type CallerInfo struct { } ``` -其中`Error`为接口类型,是`error`接口类型的扩展,用于给错误增加调用栈信息,同时支持错误的多级嵌套包装,支持支持错误码格式。为了使用方便,我们可以定义以下的辅助函数: +其中`Error`为接口类型,是`error`接口类型的扩展,用于给错误增加调用栈信息,同时支持错误的多级嵌套包装,支持错误码格式。为了使用方便,我们可以定义以下的辅助函数: ```go func New(msg string) error From 1b5310f7547a5191d4687d94e0e6a9d32be61431 Mon Sep 17 00:00:00 2001 From: apple <2571583272@qq.com> Date: Fri, 25 May 2018 19:11:43 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E7=BB=A7=E7=BB=AD=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E9=94=99=E5=88=AB=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch1-basic/ch1-06-goroutine.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ch1-basic/ch1-06-goroutine.md b/ch1-basic/ch1-06-goroutine.md index 33cff93..e450217 100644 --- a/ch1-basic/ch1-06-goroutine.md +++ b/ch1-basic/ch1-06-goroutine.md @@ -889,7 +889,7 @@ func main() { 当并发体超时或`main`主动停止工作者Goroutine时,每个工作者都可以安全退出。 -Go语言是带内存自动回收的特性,因此内存一般不会泄漏。在前面素数筛的例子中,`GenerateNatural`和`PrimeFilter`函数内部都启动了新的Goroutine,当`main`函数不再使用管道时后台Goroutine有泄漏的风险。我们可以通过`context`包来避免做个问题,下面是改进的素数筛实现: +Go语言是带内存自动回收的特性,因此内存一般不会泄漏。在前面素数筛的例子中,`GenerateNatural`和`PrimeFilter`函数内部都启动了新的Goroutine,当`main`函数不再使用管道时后台Goroutine有泄漏的风险。我们可以通过`context`包来避免这个问题,下面是改进的素数筛实现: ```go // 返回生成自然数序列的管道: 2, 3, 4, ...