"Do not communicate by sharing memory; instead, share memory by communicating." ——effective go
上面这条go语言的哲学中的理念反映到具体的代码中,就是go语言所提供的channel,这是一种强大易用的机制,单稍不留神,就会出现问题Channel简介
让我们先来写一个简单的channel例子:
package mainfunc main() { fooChan := make(chan int, 1) fooChan <- 1 val := <-fooChan print(val) }
这里我们用make创建了fooChan这个可以缓存1个int单位的chanel,将整数1加入到fooChan,并在下一条指令中取出并输出。在go语言中,我们可以创建built-in类型的channel,也可以创建custom-defined类型的channel
这里要注意这段代码:fooChan := make(chan int, 1)
make的第二个参数表示这个channel可以缓存多少条输入,如果我们这样写:
fooChan := make(chan int)
则表示创建了一个没有缓存的channel,当我们向一个没有缓存的channel中写入值的时候,我们的线程将会被阻塞。
goroutine简介
在多核CPU越来越普及的今天,为了在充分利用多核优势的同时减轻多线程编程的复杂度,go语言为我们提供了goroutine这个go语言引以为傲的工具。简单来讲,go语言支持语言层面的多线程编程,这是非常难得的,而且是划时代的。
下面是使用goroutine的一个例子:package mainimport "sync"func main() { var wait sync.WaitGroup wait.Add(1) go func(){ print("Hello Goroutine") wait.Done() }() wait.Wait()}
注意go func(){...}()
这段代码,这是在go语言中启动一个goroutine的方式,使用go关键字后面接一个函数,表示需要goroutine来运行的函数,这个函数可以接收任意参数,在这里我们使用一个无参数的函数。
channel和goroutine结合使用
channel和goroutine最直接的联合使用方式是生产-消费模式:
package mainimport "time"func main() { outputs := make(chan string) go func(){ for { outputs <- "goroutine 1\n"; time.Sleep(time.Second) } }() go func() { for { outputs <- "goroutine 2\n"; time.Sleep(time.Second) } }() for s := range outputs{ print(s) }}
主线程会一直执行for s := range outputs
这行代码,并输出其他goroutine写入的数据。用这样的方法,我们可以将一个很复杂的计算进行拆分,分配给不同的CPU内核去执行以提高总体执行效率。
下一步
channel和goroutine的简单使用就这么多,但是其中有很多需要注意的地方在本篇文章中没有提及,我会在后面的文章中详细解析。