gorouting
只需在要让Goroutine执行的函数或方法前加上关键字go即可
启动一个新的协程时,会立即返回执行下一行代码,忽略该协程返回的任何值
channel
go通过channel实现协程间的通信
channel 是有类型的管道,采用关键字chan 加上类型做声明。赋值取值采用符号”<-“
和 map 与 slice 一样,channel 使用前必须创建:
var ch chan int //声明通道
ch := make(chan int)
单向通道
package main
import "fmt"
//Send only
func func1(ch chan<- int) {
ch <- 10
}
func main() {
/*ch := make(chan<- int)
go func1(ch)*/
// invalid operation: <-ch (receive from send-only type chan<- int)
//fmt.Println(<- ch)
// ch是单向通道,只能将数据存到ch
/**
*ch 在main函数中创建是双向通道,
*在协程中将双向通道隐式转换为单向通道,只可以将数据存入通道
*/
ch := make(chan int)
go func1(ch)
fmt.Println(<-ch)
}
for range 遍历channel
package main
import "fmt"
func produce(ch chan int) {
for i:=0; i<10; i++{
ch <- i
}
close(ch)
}
func produce1(ch chan int) {
for i:=0; i<10; i++{
ch <- i
}
close(ch)
}
func main() {
ch := make(chan int)
go produce(ch)
/*for {
v,ok := <-ch
if !ok {
break
}
fmt.Println(v)
}*/
// for range 用于在一个信道关闭之前,从信道接受数据
for v :=range ch {
fmt.Println(v)
}
}
缓冲信道
通过make创建channel时,指定capacity,可以创建缓冲信道。示例如下:
ch := make(chan int, 1024)
WaitGroup
WaitGroup 用于实现工作池
package main
import (
"fmt"
"sync"
"time"
)
// 注意这里WaitGroup采用的是传地址的方式。若采用传值,每个子协程会得到一份WaitGroup的拷贝,程序不能正常结束
func process(i int, wg *sync.WaitGroup){
fmt.Println("started Goroutine ", i)
time.Sleep(2 * time.Second)
fmt.Printf("Goroutine %d ended\n", i)
wg.Done() // -1
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1) // +1
go process(i, &wg)
}
wg.Wait() // 阻塞等待,直到所有协程结束
fmt.Println("done")
}
工作池
工作池核心功能如下:
- 在主协程中创建一个工作池,监听一个等待输入型作业缓冲通道
- 将作业添加到该输入型缓冲通道中
- 作业完成后,再将结果写入一个输出型缓冲通道
- 从输出型通道读取并打印结果
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
type Job struct {
id int
randomno int
}
type Result struct {
job Job
sumofdigits int
}
var jobs = make(chan Job, 10)
var results = make(chan Result, 10)
func digits(num int) int {
sum := 0
no := num
for no != 0 {
digit := no % 10
sum += digit
no = no / 10
}
//time.Sleep(2*time.Second)
return sum
}
func worker(wg *sync.WaitGroup) {
for job := range jobs {
output := Result{job, digits(job.randomno)}
results <- output
}
wg.Done()
}
// 创建工作池
func createWorkerPool(noOfWorkers int) {
var wg sync.WaitGroup
for i := 0; i < noOfWorkers; i++ {
wg.Add(1)
go worker(&wg)
}
wg.Wait()
close(results)
}
//创建作业
func allocate(noOfJobs int) {
for i := 0; i < noOfJobs; i++ {
randomno := rand.Intn(999)
job := Job{i, randomno}
jobs <- job
}
close(jobs)
}
func result(done chan bool) {
for result := range results {
fmt.Printf("Job id %d, input random no %d , sum of digits %d\n", result.job.id, result.job.randomno, result.sumofdigits)
}
done <- true
}
func main() {
sTime := time.Now()
noOfJobs := 100 // 初始作业数为100
go allocate(noOfJobs)
done := make(chan bool)
go result(done)
noOfWorkers := 50 //初始工作池大小为10
createWorkerPool(noOfWorkers)
<- done
eTime := time.Now()
fmt.Println(eTime.Sub(sTime))
}
Mutex
package main
import (
"fmt"
"sync"
)
var x = 0
func incr(wg *sync.WaitGroup, mutex *sync.Mutex) {
mutex.Lock()
x = x + 1
mutex.Unlock()
wg.Done()
}
// 利用通道代替互斥量机制
func incr2(group *sync.WaitGroup,ch chan bool) {
ch<- true
x = x + 1
<-ch
group.Done()
}
func main() {
var wg sync.WaitGroup
//var mutex sync.Mutex
ch := make(chan bool, 1)
for i := 0; i < 1000; i++ {
wg.Add(1)
//go incr(&wg, &mutex)
go incr2(&wg, ch)
}
wg.Wait()
fmt.Println(x)
}