七叶笔记 » golang编程 » Golang之并发

Golang之并发

写在前面:

0x01 — 使用并发

在Golang中运行并发很容易,加入有个函数 f(), 直接使用关键字 go f() 即可运行:

 package main

import (
   "fmt"
   "testing"
   "time"
)

func printInfo(n string, l []int) {
   fmt.Println(n, "正在输出")
   for i:=0; i < len(l);i++ {
      fmt.Printf("%d \t", l[i])
   }
   fmt.Println("\n",n,"输出结束")
}

func TestGo(t *testing.T) {
   // 定义一个整型切片
   var li = []int{10,11,12,13,14,15,16,17,18,19}
   t.Log("准备输出")
go printInfo("协程1", li) // 启动协程
go printInfo("协程2", li) // 启动协程
   t.Log("输出结束")
   time.Sleep(time.Second) // 睡眠一秒中
}  

执行一次输出:

 === RUN   TestGo
    goroutine_test.go:23: 准备输出
    goroutine_test.go:28: 输出结束
协程2 正在输出
10 11 12 13 14 15 16 17 18 19 
 协程2 输出结束
协程1 正在输出
10 11 12 13 14 15 16 17 18 19 
 协程1 输出结束
--- PASS: TestGo (1.00s)
PASS  

再执行一次:

 === RUN   TestGo
    goroutine_test.go:23: 准备输出
    goroutine_test.go:28: 输出结束
协程1 正在输出
协程2 正在输出
10 11 12 13 14 15 16 17 18 19 
 协程1 输出结束
10 11 12 13 14 15 16 17 18 19 
 协程2 输出结束
--- PASS: TestGo (1.01s)
PASS  

从以上代码中可以看到,Info1和Info2这两个函数是并发运行的,顺序是无法确定的。

在测试函数中可以看到我在代码最后增加了一个time.Sleep方法,睡眠了1秒钟,是由于如果不睡眠,可能在并发协程还未执行,主程序就退出了,导致协程直接终止。

0x02 — 并发等待

为了等我们协程运行结束,同时不使用这种等待的low操作,可以使用内置的wait函数:

 package main

import (
   "fmt"
   "sync"
   "testing"
)

func printInfo(n string, l []int, wg * sync.WaitGroup) {
   fmt.Println(n, "正在输出")
   for i:=0; i < len(l);i++ {
      fmt.Printf("%d \t", l[i])
   }
   fmt.Println("\n",n,"输出结束")
   wg.Done() // 协程运行结束,通过Down方法释放
}

func TestGo(t *testing.T) {
   // 定义一个同步等待并发变量
   var wait sync.WaitGroup
   // 定义一个整型切片
   var li = []int{10,11,12,13,14,15,16,17,18,19}
   t.Log("准备输出")
   // 我们有两个协程,参数为2,参数的值会在协程中会被减去直到减为0,则执行指定函数
   wait.Add(2)
   go printInfo("协程1", li, &wait) // 启动协程
   go printInfo("协程2", li, &wait) // 启动协程
   wait.Wait() // 等待协程结束后,会调用
   t.Log("输出结束")
   //time.Sleep(time.Second) // 睡眠一秒中
}  

以上是waitgroup使用方式,需要注意的是在两个goroutine函数中Done方法的调用指向是一个waitGroup对象。

0x03 — 并发控制

并发控制如果不借用三方库可以使用channel来实现,channel会在下一章节学习

0x02 — 总结

Golang goroutine很容易创建且开销较小,goroutine是由Golang自己调度,而不是系统,在协程间进行通信时,尽量遵循一个原则: 不要通过共享来通信,而要通过通信来共享 。后面我会介绍下通道的使用,在Golang中,通道很好地承接了通信的功能。

相关文章