首先咱们来看线程,在golang里面也叫goroutinegolang
在读这篇文章以前,咱们须要了解一下并发与并行。golang的线程是一种并发机制,而不是并行。它们之间的区别你们能够上网搜一下,网上有不少的介绍。
多线程
下面咱们先来看一个例子吧并发
import(函数
"fmt"spa
)
线程
funcmain(){it
go fmt.Println("1")
fmt.Println("2")
}
在golang里面,使用go这个关键字,后面再跟上一个函数就能够建立一个线程。后面的这个函数能够是已经写好的函数,也能够是一个匿名函数import
funcmain(){
匿名函数
vari=3循环
go func(a int) {
fmt.Println(a)
fmt.Println("1")
}(i)
fmt.Println("2")
}
上面的代码就建立了一个匿名函数,而且还传入了一个参数i,下面括号里的i是实参,a是形参。
那么上面的代码能按照咱们预想的打印一、二、3吗?告诉大家吧,不能,程序只能打印出2。下面我把正确的代码贴出来吧
import(
"fmt"
"time"
)
funcmain(){
var i = 3
go func(a int) {
fmt.Println(a)
fmt.Println("1")
}(i)
fmt.Println("2") time.Sleep(1 * time.Second)
}
我只是在最后加了一行让主线程休眠一秒的代码,程序就会依次打印出二、三、1。
那为何会这样呢?由于程序会优先执行主线程,主线程执行完成后,程序会当即退出,没有多余的时间去执行子线程。若是在程序的最后让主线程休眠1秒钟,那程序就会有足够的时间去执行子线程。
线程先讲到这里,下面咱们来看看通道吧。
通道又叫channel,顾名思义,channel的做用就是在多线程之间传递数据的。
建立无缓冲channel
chreadandwrite :=make(chan int)
chonlyread := make(<-chan int) //建立只读channel
chonlywrite := make(chan<- int) //建立只写channel
下面咱们来看一个例子:
ch :=make(chan int)
ch <- 1
go func() {
<-ch
fmt.Println("1")
}()
fmt.Println("2")
这段代码执行时会出现一个错误: :=make(chan int,1)
ch <- 1
go func() {
v := <-ch
fmt.Println(v)
}()
time.Sleep(1 * time.Second)
fmt.Println("2")
这样的话程序就会依次打印出一、2
二、把ch<-1这一行代码放到子线程代码的后面,代码以下:
ch :=make(chan int)
go func() {
v := <-ch
fmt.Println(v)
}()
ch <- 1
fmt.Println("2")
这里就不用让主线程休眠了,由于channel在主线程中被赋值后,主线程就会阻塞,直到channel的值在子线程中被取出。
最后咱们看一个生产者和消费者的例子:
import (
"fmt"
"time"
)
func produce(p chan<- int) {
for i := 0; i < 10; i++ {
p <- i
fmt.Println("send:", i)
}
}
func consumer(c <-chan int) {
for i := 0; i < 10; i++ {
v := <-c
fmt.Println("receive:", v)
}
}
func main() {
ch := make(chan int)
go produce(ch)
go consumer(ch)
time.Sleep(1 * time.Second)
}
在这段代码中,由于channel是没有缓冲的,因此当生产者给channel赋值后,生产者这个线程会阻塞,直到消费者线程将channel中的数据取出。消费者第一次将数据取出后,进行下一次循环时,消费者的线程也会阻塞,由于生产者尚未将数据存入,这时程序会去执行生产者的线程。程序就这样在消费者和生产者两个线程间不断切换,直到循环结束。
下面咱们再看一个带缓冲的例子:
import (
"fmt"
"time"
)
func produce(p chan<- int) {
for i := 0; i < 10; i++ {
p <- i
fmt.Println("send:", i)
}
}
func consumer(c <-chan int) {
for i := 0; i < 10; i++ {
v := <-c
fmt.Println("receive:", v)
}
}
func main() {
ch := make(chan int, 10)
go produce(ch)
go consumer(ch)
time.Sleep(1 * time.Second)
}
在这个程序中,缓冲区能够存储10个int类型的整数,在执行生产者线程的时候,线程就不会阻塞,一次性将10个整数存入channel,在读取的时候,也是一次性读取。