Go 中的 Goroutines
Goroutines 允许您能够并行的执行任务——为什么又出来了这么一个新词儿?虽然现在已经有很多形容并行的词了,比如线程、协程、进程等等,但是没有一个已有的词汇能精确地表达出Goroutines的内涵,一个Goroutines就是一个与其它的Goroutine在同一地址空间中并行执行的函数或者方法,一个运行中的程序有一个或者多个Goroutines组成,Go官方文档如下面这么说道:
Goroutines被复用到多个系统线程上,所以,如果某一个Goroutine阻塞了,并不会影响其它的Goroutine。 Goroutines为我们隐藏了很多的内部的并行机制,这样的设计让语言的设计者可以根据需要修改它底层并行的实现,以改进其运行性能或者进行硬件优化,而作为语言使用者的我们则不需要修改任何一个代码,就能获得性能的提升。
在大多数程序中,我们都是按顺序执行的,因为作为用户的人的处理能力是远远不及计算机的,比如当我们在写代码的时候,我们敲击键盘的速度比计算机处理敲击的速度是慢得多的,所以,计算机在这种情况下一直是处于等待我们的输入的状态。但是对于一台每一秒都处理成千上万请求的服务器来说,这种顺序执行的方法显然是不可能的,如果一百个人同时请求,我们不可能按顺序的执行每一个用户的请求,这个时候就需要并发,在Go中,我们使用Goroutines。
Goroutines与普通的函数没有什么不一样的,只是它执行它的时候,需要在函数的名称前面使用一个 go 关键字,如果我们 myFunc() 是一个方法,那么如果要让它以一个Goroutine的方式执行,只需要 go myFunc() 即可——这将使得它以一个新的线程运行,让我们来做一个简单的示例:
package main
import "fmt"
func LoopIt(times int) {
for i := 0; i < times; i++ {
fmt.Printf("%dt", i)
}
fmt.Println("--Loop End--")
}
func main() {
LoopIt(10)
LoopIt(10)
}输出为:
0 1 2 3 4 5 6 7 8 9 --Loop End--
0 1 2 3 4 5 6 7 8 9 --Loop End--然后我们对程序做一个很小的改动:
//...
func main() {
go LoopIt(10)
LoopIt(10)
}它的输出结果可能就成为:
0 0 1 2 1 3 2 4 3 5 4 6 5 7 6 8 7 9 8 --Loop End--
--Loop End--为什么会有这样的区别?因为当我启动一个 Goroutine 之后,LoopIt这个函数立马就会执行,但是它并不会阻塞整个程序,所以,它开始执行之后,它后面的函数也会开始执行,后面的函数就是一个普通的函数,所以它会顺序执行,这使得两人个函数同时运行了,所以我们上面的输出中,这样一来,LoopIt 会一直输出数字,而由于go LoopIt也在执行,它也会输出数据,所以就出现了上面那种情况,这两人个 LoopIt并行了。
再来看看下面这个例子:
package main
import (
"fmt"
"time"
)
func simulateEvent(name string, timeInSecs string) {
fmt.Println("Started ", name, ": Should take", timeInSecs, "seconds")
du, _ := time.ParseDuration(timeInSecs)
time.Sleep(du)
fmt.Println("Finished ", name)
}
func main() {
simulateEvent("First", "10s")
simulateEvent("Second", "6s")
simulateEvent("Third", "3s")
}输出结果为:
Started First : Should take 10s seconds
Finished First
Started Second : Should take 6s seconds
Finished Second
Started Third : Should take 3s seconds
Finished Third这是一个顺序执行的程序,所以,我们可以看到,必须是第一个函数执行完了之后才执行第二个函数,但是我们再来看看下面这个示例:
package main
import (
"fmt"
"time"
)
func simulateEvent(name string, timeInSecs string) {
fmt.Println("Started ", name, ": Should take", timeInSecs, "seconds")
du, _ := time.ParseDuration(timeInSecs)
time.Sleep(du)
fmt.Println("Finished ", name)
}
func main() {
go simulateEvent("First", "10s")
go simulateEvent("Second", "6s")
go simulateEvent("Third", "3s")
wait, _ := time.ParseDuration("15s")
time.Sleep(wait)
fmt.Println("Exited")
}输出为:
Started First : Should take 10s seconds
Started Second : Should take 6s seconds
Started Third : Should take 3s seconds
Finished Third
Finished Second
Finished First
Exited所有的函数都同时运行了,然后因为第三个函数只暂时3秒,所以它最先运行完成,而第二个第二完成,第一个因为要暂时10秒,所以最后完成,我们在 main() 函数中使用暂时了程序15秒,以让上面的三个 Goroutines运行完成之后才退出程序。
评论已关闭