针对这本书做了一些细致化的改进

This commit is contained in:
astaxie
2013-01-15 17:15:02 +08:00
parent 9bcbe357be
commit f48f2f9119
8 changed files with 1386 additions and 1130 deletions

3
2.2.md
View File

@@ -443,9 +443,6 @@ slice有一些简便的操作
bool false bool false
string "" string ""
## links ## links
* [目录](<preface.md>) * [目录](<preface.md>)
* 上一章: [你好,Go](<2.1.md>) * 上一章: [你好,Go](<2.1.md>)

56
2.3.md
View File

@@ -455,6 +455,62 @@ Go程序会自动调用`init()`和`main()`,所以你不需要在任何地方
![](images/2.3.init.png?raw=true) ![](images/2.3.init.png?raw=true)
### import
我们在写Go代码的时候经常用到import这个命令用来导入包文件而我们经常看到的方式参考如下
import(
"fmt"
)
然后我们代码里面可以通过如下的方式调用
fmt.Println("hello world")
上面这个fmt是Go语言的标准库其实是去goroot下去加载该模块当然Go的import还支持如下两种方式来加载自己写的模块
1. 相对路径
import “./model” //当前文件同一目录的model目录但是不建议这种方式来import
2. 绝对路径
import “shorturl/model” //加载gopath/src/shorturl/model模块
上面展示了一些import常用的几种方式但是还有一些特殊的import让很多新手很费解下面我们来一一讲解一下到底是怎么一回事
1. 点操作
我们有时候会看到如下的方式导入包
import(
. "fmt"
)
这个点操作的含义就是这个包导入之后在你调用这个包的函数时你可以省略前缀的包名也就是前面你调用的fmt.Println("hello world")可以省略的写成Println("hello world")
2. 别名操作
别名操作顾名思义我们可以把包命名成另一个我们用起来容易记忆的名字
import(
f "fmt"
)
别名操作的话调用包函数时前缀变成了我们的前缀即f.Println("hello world")
3. _操作
这个操作经常是让很多人费解的一个操作符请看下面这个import
import (
"database/sql"
_ "github.com/ziutek/mymysql/godrv"
)
_操作其实是引入该包而不直接使用包里面的函数而是调用了该包里面的init函数。
## links ## links
* [目录](<preface.md>) * [目录](<preface.md>)

67
2.7.md
View File

@@ -2,15 +2,15 @@
有人把Go比作21世纪的C语言第一是因为Go语言设计简单第二21世纪最重要的就是并行程序设计而GO从语言层面就支持了并行。 有人把Go比作21世纪的C语言第一是因为Go语言设计简单第二21世纪最重要的就是并行程序设计而GO从语言层面就支持了并行。
## Goroutines ## goroutine
Goroutines是Go并行设计的核心。Goroutines说到底其实就是线程,但是他比线程更小,十几个Goroutines可能体现在底层就是五六个线程Go语言内部帮你实现了这些Goroutines之间的内存共享。Go语言的作者经常说着这样一句话不要通过共享来通信而要通过通信来共享 goroutine是Go并行设计的核心。goroutine说到底其实就是线程但是他比线程更小十几个goroutine可能体现在底层就是五六个线程Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB)当然会根据相应的数据伸缩。也正因为如此可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便
Goroutines是通过Go的runtime管理的一个线程管理器。Goroutines通过`go`关键字实现了,其实就是一个普通的函数。 goroutine是通过Go的runtime管理的一个线程管理器。goroutine通过`go`关键字实现了,其实就是一个普通的函数。
go hello(a, b, c) go hello(a, b, c)
通过关键字go就启动了一个Goroutines。我们来看一个例子 通过关键字go就启动了一个goroutine。我们来看一个例子
package main package main
@@ -43,9 +43,14 @@ Goroutines是通过Go的runtime管理的一个线程管理器。Goroutines通过
hello hello
我们可以看到go关键字很方便的就实现了并发编程。 我们可以看到go关键字很方便的就实现了并发编程。
runtime.Gosched()表示让CPU把时间片让给别人 上面的多个goroutine运行在同一个进程里面共享内存数据不过设计上我们要遵循不要通过共享来通信而要通过通信来共享
> runtime.Gosched()表示让CPU把时间片让给别人,结束当前的goroutine。
>默认情况下,调度器仅使用单线程,也就是说只实现了并发。想要发挥多核处理器的并行,需要在我们的程序中显示的调用 runtime.GOMAXPROCS(n) 告诉调度器同时使用多个线程。GOMAXPROCS 设置了同时运行逻辑代码的系统线程的最大数量并返回之前的设置。如果n < 1不会改变当前设置。以后Go的新版本中调度得到改进后这将被移除。这里有一篇rob介绍的关于并发和并行的文章http://concur.rspace.googlecode.com/hg/talk/concur.html#landing-slide
## channels ## channels
Goroutines运行在相同的地址空间,因此访问共享内存必须做好同步。那么Goroutines之间如何进行数据的通信呢Go提供了一个很好的通信机制channel。channel可以与Unix shell 中的双向管道做类比可以通过它发送或者接收值。这些值只能是特定的类型channel类型。定义一个channel 也需要定义发送到channel 的值的类型。注意必须使用make 创建channel goroutine运行在相同的地址空间因此访问共享内存必须做好同步。那么goroutine之间如何进行数据的通信呢Go提供了一个很好的通信机制channel。channel可以与Unix shell 中的双向管道做类比可以通过它发送或者接收值。这些值只能是特定的类型channel类型。定义一个channel时也需要定义发送到channel的值的类型。注意必须使用make 创建channel
ci := make(chan int) ci := make(chan int)
cs := make(chan string) cs := make(chan string)
@@ -81,7 +86,7 @@ channel通过操作符`<-`来接收和发送数据
fmt.Println(x, y, x + y) fmt.Println(x, y, x + y)
} }
默认情况下channel接收和发送数据都是阻塞的除非另一端已经准备好这样就使得Goroutines同步变的更加的简单而不需要显式的lock。所谓阻塞也就是如果读取value := <-ch它将会被阻塞直到有数据接收。其次任何发送ch<-5将会被阻塞直到数据被读出。无缓冲channel 是在多个goroutine之间同步很棒的工具。 默认情况下channel接收和发送数据都是阻塞的除非另一端已经准备好这样就使得Goroutines同步变的更加的简单而不需要显式的lock。所谓阻塞也就是如果读取value := <-ch它将会被阻塞直到有数据接收。其次任何发送ch<-5将会被阻塞直到数据被读出。无缓冲channel是在多个goroutine之间同步很棒的工具。
## Buffered Channels ## Buffered Channels
上面我们介绍了默认的非缓存类型的channel不过Go也允许指定channel的缓冲大小很简单就是channel可以存储多少元素。ch:= make(chan bool, 4)创建了可以存储4个元素的bool 型channel。在这个channel 中前4个元素可以无阻塞的写入。当写入第5个元素时代码将会阻塞直到其他goroutine从channel 中读取一些元素,腾出空间。 上面我们介绍了默认的非缓存类型的channel不过Go也允许指定channel的缓冲大小很简单就是channel可以存储多少元素。ch:= make(chan bool, 4)创建了可以存储4个元素的bool 型channel。在这个channel 中前4个元素可以无阻塞的写入。当写入第5个元素时代码将会阻塞直到其他goroutine从channel 中读取一些元素,腾出空间。
@@ -172,8 +177,6 @@ channel通过操作符`<-`来接收和发送数据
fibonacci(c, quit) fibonacci(c, quit)
} }
虽然goroutine是并发执行的但是它们并不是并行运行的。如果不告诉Go额外的东西同一时刻只会有一个goroutine执行逻辑代码。利用runtime.GOMAXPROCS(n)可以设置goroutine并行执行的数量。GOMAXPROCS 设置了同时运行逻辑代码的系统线程 的最大数量并返回之前的设置。如果n < 1不会改变当前设置。以后Go的新版本中调度得到改进后这将被移除。
`select`里面还有default语法`select`其实就是类似switch的功能default就是当监听的channel都没有准备好的时候默认执行的select不再阻塞等待channel `select`里面还有default语法`select`其实就是类似switch的功能default就是当监听的channel都没有准备好的时候默认执行的select不再阻塞等待channel
select { select {
@@ -183,6 +186,52 @@ channel通过操作符`<-`来接收和发送数据
// 当c阻塞的时候执行这里 // 当c阻塞的时候执行这里
} }
## 超时
有时候会出现goroutine阻塞的情况那么我们如何避免整个的程序进入阻塞的情况呢我们可以利用select来设置超时通过如下的方式实现
func main() {
c := make(chan int)
o := make(chan bool)
go func() {
for {
select {
case v := <- c:
println(v)
case <- time.After(5 * time.Second):
println("timeout")
o <- true
break
}
}
}()
<- o
}
## runtime goroutine
runtime包中有几个处理goroutine的函数
- Goexit
退出当前执行的goroutine但是defer函数还会继续调用
- Gosched
让出当前goroutine的执行权限调度器安排其他等待的任务运行并在下次某个时候从该位置恢复执行。
- NumCPU
返回 CPU 核数量
- NumGoroutine
返回正在执⾏行和排队的任务总数
- GOMAXPROCS
用来设置可以运行的CPU核数
## links ## links
* [目录](<preface.md>) * [目录](<preface.md>)

2
7.4.md
View File

@@ -345,4 +345,4 @@ Unix用户已经很熟悉什么是`pipe`了,`ls | grep "beego"`类似这样的
## links ## links
* [目录](<preface.md>) * [目录](<preface.md>)
* 上一节: [正则处理](<7.3.md>) * 上一节: [正则处理](<7.3.md>)
* 下一节: [小结](<7.5.md>) * 下一节: [文件操作](<7.5.md>)

152
7.5.md
View File

@@ -1,7 +1,153 @@
# 7.5 小结 # 7.5 文件操作
这一章给大家介绍了一些文本处理的工具包括XML、JSON、正则和模板技术XML和JSON是数据交互的工具通过XML和JSON你可以表达各种含义通过正则你可以处理文本(搜索、替换、截取)通过模板技术你可以展现这些数据给用户。这些都是你开发Web应用过程中需要用到的技术通过这个小节的介绍你能够了解如何处理文本、展现文本 在任何计算机设备中文件是都是必须的对象而在Web编程中,文件的操作一直是Web程序员经常遇到的问题,文件操作在Web应用中是必须的,非常有用的,我们经常遇到生成文件目录,文件(夹)编辑等操作,现在我把Go中的这些操作做一详细总结并实例示范如何使用
## 目录操作
文件操作的大多数函数都是在os包里面下面列举了几个目录操作的
- func Mkdir(name string, perm FileMode) error
创建名称为name的目录权限设置是perm例如0777
- func MkdirAll(path string, perm FileMode) error
根据path创建多级子目录例如astaxie/test1/test2。
- func Remove(name string) error
删除名称为name的目录当目录下有文件或者其他目录是会出错
- func RemoveAll(path string) error
根据path删除多级子目录如果path是单个名称那么该目录不删除。
下面是演示代码:
package main
import (
"fmt"
"os"
)
func main() {
os.Mkdir("astaxie", 0777)
os.MkdirAll("astaxie/test1/test2", 0777)
err := os.Remove("astaxie")
if err != nil {
fmt.Println(err)
}
os.RemoveAll("astaxie")
}
## 文件操作
### 建立与打开文件
新建文件可以通过如下两个方法
- func Create(name string) (file *File, err Error)
根据提供的文件名创建新的文件返回一个文件对象默认权限是0666的文件返回的文件对象是可读写的。
- func NewFile(fd uintptr, name string) *File
根据文件描述符创建相应的文件,返回一个文件对象
通过如下两个方法来打开文件:
- func Open(name string) (file *File, err Error)
该方法打开一个名称为name的文件但是是只读方式内部实现其实调用了OpenFile。
- func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
打开名称为name的文件flag是打开的方式只读、读写等perm是权限
### 写文件
写文件函数:
- func (file *File) Write(b []byte) (n int, err Error)
写入byte类型的信息到文件
- func (file *File) WriteAt(b []byte, off int64) (n int, err Error)
在指定位置开始写入byte类型的信息
- func (file *File) WriteString(s string) (ret int, err Error)
写入string信息到文件
写文件的示例代码
package main
import (
"fmt"
"os"
)
func main() {
userFile := "astaxie.txt"
fout, err := os.Create(userFile)
defer fout.Close()
if err != nil {
fmt.Println(userFile, err)
return
}
for i := 0; i < 10; i++ {
fout.WriteString("Just a test!\r\n")
fout.Write([]byte("Just a test!\r\n"))
}
}
### 读文件
读文件函数:
- func (file *File) Read(b []byte) (n int, err Error)
读取数据到b中
- func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
从off开始读取数据到b中
读文件的示例代码:
package main
import (
"fmt"
"os"
)
func main() {
userFile := "asatxie.txt"
fl, err := os.Open(userFile)
defer fl.Close()
if err != nil {
fmt.Println(userFile, err)
return
}
buf := make([]byte, 1024)
for {
n, _ := fl.Read(buf)
if 0 == n {
break
}
os.Stdout.Write(buf[:n])
}
}
### 删除文件
Go语言里面删除文件和删除文件夹是同一个函数
- func Remove(name string) Error
调用该函数就可以删除文件名为name的文件
## links ## links
* [目录](<preface.md>) * [目录](<preface.md>)
* 上一节: [模板处理](<7.4.md>) * 上一节: [模板处理](<7.4.md>)
* 下一节: [Web服务](<8.md>) * 下一节: [小结](<7.6.md>)

7
7.6.md Normal file
View File

@@ -0,0 +1,7 @@
# 7.5 小结
这一章给大家介绍了一些文本处理的工具包括XML、JSON、正则和模板技术XML和JSON是数据交互的工具通过XML和JSON你可以表达各种含义通过正则你可以处理文本(搜索、替换、截取)通过模板技术你可以展现这些数据给用户。这些都是你开发Web应用过程中需要用到的技术通过这个小节的介绍你能够了解如何处理文本、展现文本。
## links
* [目录](<preface.md>)
* 上一节: [文件操作](<7.5.md>)
* 下一节: [Web服务](<8.md>)

2
7.md
View File

@@ -1,7 +1,7 @@
# 7 文本处理 # 7 文本处理
Web开发中对于文本处理是非常重要的一部分我们往往需要对输出或者输入的内容进行处理这里的文本包括字符串、数字、Json、XMl等等。Go语言作为一门高性能的语言对这些文本的处理都有官方的标准库来支持。而且在你使用中你会发现Go标准库的一些设计相当的巧妙而且对于使用者来说也很方便就能处理这些文本。本章我们将通过四个小节的介绍让用户对Go语言处理文本有一个很好的认识。 Web开发中对于文本处理是非常重要的一部分我们往往需要对输出或者输入的内容进行处理这里的文本包括字符串、数字、Json、XMl等等。Go语言作为一门高性能的语言对这些文本的处理都有官方的标准库来支持。而且在你使用中你会发现Go标准库的一些设计相当的巧妙而且对于使用者来说也很方便就能处理这些文本。本章我们将通过四个小节的介绍让用户对Go语言处理文本有一个很好的认识。
XML是目前很多标准接口的交互语言很多时候和一些Java编写的webserver进行交互都是基于XML标准进行交互7.1小节将介绍如何处理XML文本我们使用XML之后发现它太复杂了现在很多互联网企业对外的API大多数采用了JSON格式这种格式描述简单但是又能很好的表达意思7.2小节我们将讲述如何来处理这样的JSON格式数据。正则是一个让人又爱又恨的工具它处理文本的能力非常强大我们在前面表单验证里面已经有所领略它的强大7.3小节将详细的更深入的讲解如何利用好Go的正则。Web开发中一个很重要的部分就是MVC分离在Go语言的Web开发中V有一个专门的包来支持`template`,7.4小节将详细的讲解如何使用模版来进行输出内容。 XML是目前很多标准接口的交互语言很多时候和一些Java编写的webserver进行交互都是基于XML标准进行交互7.1小节将介绍如何处理XML文本我们使用XML之后发现它太复杂了现在很多互联网企业对外的API大多数采用了JSON格式这种格式描述简单但是又能很好的表达意思7.2小节我们将讲述如何来处理这样的JSON格式数据。正则是一个让人又爱又恨的工具它处理文本的能力非常强大我们在前面表单验证里面已经有所领略它的强大7.3小节将详细的更深入的讲解如何利用好Go的正则。Web开发中一个很重要的部分就是MVC分离在Go语言的Web开发中V有一个专门的包来支持`template`,7.4小节将详细的讲解如何使用模版来进行输出内容。7.5小节讲详细介绍如何进行文件和文件夹的操作。
## 目录 ## 目录
* 1. [XML处理](7.1.md) * 1. [XML处理](7.1.md)

View File

@@ -40,12 +40,13 @@
- 6.3 [session存储](6.3.md) - 6.3 [session存储](6.3.md)
- 6.4 [预防session劫持](6.4.md) - 6.4 [预防session劫持](6.4.md)
- 6.5 [小结](6.5.md) - 6.5 [小结](6.5.md)
* 7.[文本处理](7.md) * 7.[文本文件处理](7.md)
- 7.1 [XML处理](7.1.md) - 7.1 [XML处理](7.1.md)
- 7.2 [JSON处理](7.2.md) - 7.2 [JSON处理](7.2.md)
- 7.3 [正则处理](7.3.md) - 7.3 [正则处理](7.3.md)
- 7.4 [模板处理](7.4.md) - 7.4 [模板处理](7.4.md)
- 7.5 [小结](7.5.md) - 7.5 [文件操作](7.5.md)
- 7.6 [小结](7.6.md)
* 8.[Web服务](8.md) * 8.[Web服务](8.md)
- 8.1 [Socket编程](8.1.md) - 8.1 [Socket编程](8.1.md)
- 8.2 [WebSocket](8.2.md) - 8.2 [WebSocket](8.2.md)