goroutine和channel
一次只做一件事并不总是完成任务最快的方法。一些大问题可以分解成小任务。goroutine可以让程序同时处理几个不同的任务。goroutine可以使用channel来协调它们的工作,channel允许goroutine互相发送数据并同步,这样一个goroutine就不会领先于另一个goroutine。goroutine让你充分利用具有多处理器的计算机,让程序运行得尽可能快!
检索网页
package main import ( "fmt" "io/ioutil" "net/http" ) func getUrl(url string) { get, err := http.Get(url) if err!=nil { recover() panic("get err") } if get==nil{ recover() panic("body none 1") } body := get.Body f := func() { for body.Close()!=nil { fmt.Printf("Close get err") } } defer f() all, errR := ioutil.ReadAll(body) if errR != nil { recover() panic("body none 2") } fmt.Printf(string(all)) } func main() { getUrl("http://www.baidu.com") }
多任务,使用goroutine的并发性
通过同时执行多个任务来找到加快程序运行速度的方法。
将大型任务分解为可以并发运行的较小子任务,有时可能意味着程序的速度会大大提高。
goroutine允许并发:暂停一个任务来处理其他任务。在某些情况下,它们允许并行:同时处理多个任务!
在Go中,并发任务称为goroutine。其他编程语言有一个类似的概念,叫作线程,但是goroutine比线程需要更少的计算机内存,启动和停止的时间更少,这意味着你可以同时运行更多的goroutine。
它们也更容易使用。要启动另一个goroutine,可以使用go语句,它只是一个普通的函数或方法调用,前面有go关键字:
使用goroutine
没有使用
package main import ( "fmt" "time" ) func main() { now := time.Now() for i:=0;i<30;i++ { func() { time.Sleep(100) }() } elapsed := time.Since(now) fmt.Println("\n该函数执行完成耗时:", elapsed) }

go语句不能使用返回值
切换到goroutine带来了另一个需要解决的问题:我们不能在go语句中使用函数返回值。
但是goroutine之间有一种交流方式:channel。channel不仅允许你将值从一个goroutine发送到另一个goroutine,还确保在接收的goroutine尝试使用该值之前,发送的goroutine已经发送了该值。
使用channel的唯一实际方法是从一个goroutine到另一个goroutine的通信。所以为了演示channel,我们需要做一些事情:
·创建一个channel。
·编写一个函数,该函数接收一个channel作为参数。我们将在一个单独的goroutine中运行这个函数,并使用它通过channel发送值。
每个channel只携带特定类型的值,因此可能有一个channel用于int值,另一个channel用于struct类型的值。要声明包含channel的变量,可以使用chan关键字,然后是channel将携带的值的类型。
要实际创建channel,你需要调用内置的make函数(与创建映射和切片的函数相同)。传递make要创建的channel的类型(应该与要赋值给它的变量的类型相同)。
不是单独声明channel变量,在大多数情况下,使用一个短变量声明更容易:
使用channel发送和接收值
要在channel上发送值,可以使用<-运算符(这是一个小于号后面跟着一个英文破折号)。它看起来像一个箭头,从发送的值指向发送该值的channel。
你还可以使用<-运算符来接收来自channel的值,但是位置不同:你将箭头放在接收channel的左侧。(这看起来有点像你从channel中取出一个值。)
使用goroutine
package main import ( "fmt" "time" ) var ints = make(chan int) func main() { now := time.Now() for i:=0;i<30;i++ { go func() { time.Sleep(100) ints<-1 }() } n:=0 for ;n<29;n+=(<-ints) { } elapsed := time.Since(now) fmt.Println("\n该函数执行完成耗时:", elapsed) }
顺序执行
- 我们提到,channel还确保发送的goroutine在接收channel尝试使用该值之前已经发送了该值。channel通过blocking(阻塞)——暂停当前goroutine中的所有进一步操作来实现这一点。发送操作阻塞发送goroutine,直到另一个goroutine在同一channel上执行了接收操作。反之亦然:接收操作阻塞接收goroutine,直到另一个goroutine在同一channel上执行了发送操作。这个行为允许goroutine同步它们的动作——协调它们的时间.
>package main >import "time" >var ints = make(chan int) >func main() { go func() { for i:=0;i<3;i++ { time.Sleep(time.Duration(1000000000)) <-ints println("go ",i) ints<-1 } }() for i:=0;i<3;i++ { ints<-1 println("main ",i) <-ints } >}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!








