1、chan1
package main
import (
"fmt"
)
func main() {
ch := make(chan string) // 构建一个通道
go func() { // 开启一个并发匿名函数
fmt.Println("开始协程") // 通过通道通知main的协程
ch <- "signal"
fmt.Println("退出协程")
}()
fmt.Println("等待协程")
<-ch // 等待匿名协程
fmt.Println("完成")
}
2、chan2:
package main
import (
"fmt"
)
func Sum(s []int, ch chan int) {
sum := 0
for _, v := range s {
sum += v
}
ch <- sum // 把 sum 发送到通道 ch
}
func main() {
s := []int{6, 7, 8, -9, 1, 8}
ch := make(chan int)
go Sum(s[:len(s)/2], ch)
go Sum(s[len(s)/2:], ch)
a, b := <-ch, <-ch // 从通道 ch 中接收
fmt.Println(a, b, a+b)
}
后进先出
3、chan3:
package main
import "fmt"
func main() {
// 这里我们定义了一个可以存储整数类型的带缓冲通道,缓冲区大小为3
ch := make(chan int, 3)
// 因为 ch 是带缓冲的通道,我们可以同时发送两个数据
// 而不用立刻需要去同步读取数据
ch <- 6
ch <- 7
ch <- 8
// 获取这三个数据
fmt.Println(<-ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
}
4、chan4:
package main
import (
"fmt"
)
func fibonacci(n int, ch chan int) {
a, b := 0, 1
for i := 0; i < n; i++ {
ch <- a
a, b = b, a+b
}
close(ch)
}
func main() {
ch := make(chan int, 6)
go fibonacci(cap(ch), ch)
for j := range ch {
fmt.Println(j)
}
}
5、channel:
package main
func main() {
// 创建一个字符串通道
ch := make(chan string)
// 尝试将sleep通过通道发送
ch <- "sleep"
}
这里会发生死锁
package main
import (
"fmt"
"runtime"
"sync"
)
var Counter int
func Count(lock *sync.Mutex) {
lock.Lock() // 上锁
Counter++
fmt.Println("Counter =", Counter)
lock.Unlock() // 解锁
}
func main() {
lock := &sync.Mutex{}
for i := 0; i < 6; i++ {
go Count(lock)
}
for {
lock.Lock() // 上锁
c := Counter
lock.Unlock() // 解锁
runtime.Gosched() // 出让时间片
if c >= 6 {
break
}
}
}
package main
import (
"fmt"
)
func Counting(ch chan int) {
ch <- 1
fmt.Println("Counting")
}
func main() {
channels := make([]chan int, 6)
for i := 0; i < 6; i++ {
channels[i] = make(chan int)
go Counting(channels[i])
}
for _, ch := range channels {
fmt.Println(<-ch)
}
//select {
//case <- chan1:
// // 如果chan1成功读到数据
//
//case chan2 <- 1:
// // 如果成功向chan2写入数据
//
//default:
// // 默认分支
//}
//
//timeout := make(chan bool, 1)
//
//go func() {
// time.Sleep(1e9)
// timeout <- true
//}()
//
//switch {
//case <- ch:
// // 从ch中读取到数据
//
//case <- timeout:
// // 没有从ch中读取到数据,但从timeout中读取到了数据
//}
}
package main
import "fmt"
func main() {
ch := make(chan int, 2)
// 发送
go func() {
for i := 0; i < 6; i++ {
fmt.Printf("Sender: sending element %v...\n", i)
ch <- i
}
fmt.Println("Sender: close the channel...")
close(ch)
}()
// 接收
for {
elem, ok := <-ch
if !ok {
fmt.Println("Receiver: closed channel")
break
}
fmt.Printf("Receiver: received an element: %v\n", elem)
}
fmt.Println("End.")
}
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
var wg sync.WaitGroup
func init() {
rand.Seed(time.Now().UnixNano())
}
func main() {
ch := make(chan int)
wg.Add(2)
go playTableTennis("Jim", ch)
go playTableTennis("Jack", ch)
ch <- 1
wg.Wait()
}
func playTableTennis(player string, ch chan int) {
defer wg.Done()
for {
ball, ok := <-ch
if !ok {
fmt.Printf("%s has won!\n", player)
return
}
n := rand.Intn(100)
if n%13 == 0 {
fmt.Printf("player %s missed!\n", player)
close(ch)
return
}
ball++
fmt.Printf("play %s has hit the ball, his score is %d\n", player, ball)
ch <- ball
}
}
package main
import "fmt"
func main() {
ch := make(chan string, 3)
ch <- "i"
ch <- "love"
ch <- "you"
close(ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
fmt.Println(<-ch)
}
package main
import "fmt"
func main() {
var a, b int
go func() {
a = 1
fmt.Println("a:", b, " ")
}()
go func() {
b = 1
fmt.Println("b:", a, " ")
}()
}
6、channel-filter
package main
import "fmt"
// 生成自增的整数
func IntegerGenerator() chan int {
var ch chan int = make(chan int)
go func() { // 开出一个goroutine
for i := 2; ; i++ {
ch <- i // 直到通道索要数据,才把i添加进通道
}
}()
return ch
}
func Filter(in chan int, number int) chan int {
// 输入一个整数队列,筛出是number倍数的, 不是number的倍数的放入输出队列
// in: 输入队列
out := make(chan int)
go func() {
for {
i := <-in // 从输入中取一个
if i%number != 0 {
out <- i // 放入输出通道
}
}
}()
return out
}
func main() {
const max = 100 // 找出100以内的所有素数
numbers := IntegerGenerator() // 初始化一个整数生成器
number := <-numbers // 从生成器中抓一个整数(2), 作为初始化整数
for number <= max { // number作为筛子,当筛子超过max的时候结束筛选
fmt.Println(number) // 打印素数, 筛子即一个素数
numbers = Filter(numbers, number) //筛掉number的倍数
number = <-numbers // 更新筛子
}
}
7、channel-listener
package main
import (
"fmt"
)
func foo(i int) chan int {
ch := make(chan int)
go func() { ch <- i }()
return ch
}
func main() {
ch1, ch2, ch3 := foo(3), foo(6), foo(9)
ch := make(chan int)
// 开一个goroutine监视各个通道数据输出并收集数据到通道ch
go func() {
for {
// 监视ch1, ch2, ch3的流出,并全部流入通道ch
select {
case v1 := <-ch1:
ch <- v1
case v2 := <-ch2:
ch <- v2
case v3 := <-ch3:
ch <- v3
}
//timeout 是一个计时通道, 如果达到时间了,就会发一个信号出来
//timeout := time.After(1 * time.Second)
//for isTimeout := false; !isTimeout; {
// select { // 监视通道ch1, ch2, ch3, timeout通道的数据流出
// case v1 := <-ch1:
// fmt.Printf("received %d from ch1", v1)
// case v2 := <-ch2:
// fmt.Printf("received %d from ch2", v2)
// case v3 := <-ch3:
// fmt.Printf("received %d from ch3", v3)
// case <-timeout:
// isTimeout = true // 超时
// }
//}
}
}()
// 阻塞主线,取出通道ch的数据
for i := 0; i < 3; i++ {
fmt.Println(<-ch)
}
}
8、channel-quit
package main
import (
"fmt"
)
func main() {
ch, quit := make(chan int), make(chan int)
go func() {
ch <- 8 // 添加数据
quit <- 1 // 发送完成信号
}()
for isQuit := false; !isQuit; {
// 监视通道ch的数据流出
select {
case v := <-ch:
fmt.Printf("received %d from ch", v)
case <-quit:
isQuit = true // quit通道有输出,关闭for循环
}
}
}
9、channel-receive
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int) // 构建一个通道
go func() { // 开启一个并发匿名函数
for i := 6; i <= 8; i++ { // 从6循环到8
ch <- i // 发送6到8之间的数值
time.Sleep(time.Second) // 每次发送完时等待
}
}()
for receive := range ch { // 遍历接收通道数据
fmt.Println(receive) // 打印通道数据
if receive == 8 { // 当遇到数据8时, 退出接收循环
break
}
}
}
10、concurrent
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"io"
"net/http"
"os"
"runtime"
"strconv"
"sync"
"time"
)
const (
DataRoot = "./tmp/" // 存放封面图的根目录
TimeoutLimit = 10 // 设置超时时间
)
// 表示章节ID和封面URL的对应关系
type VolumeCover struct {
VolumeID int
Url string
Lock sync.Mutex
Msg chan string
Flag bool "timeout_flag"
}
// 将图片下载并保存到本地
func SaveImage(vc *VolumeCover) {
res, err := http.Get(vc.Url)
defer res.Body.Close()
if err != nil {
vc.Msg <- (strconv.Itoa(vc.VolumeID) + " HTTP_ERROR")
}
// 创建文件
dst, err := os.Create(DataRoot + strconv.Itoa(vc.VolumeID) + ".jpg")
if err != nil {
vc.Msg <- (strconv.Itoa(vc.VolumeID) + " OS_ERROR")
}
// 生成文件
io.Copy(dst, res.Body)
// goroutine通信
vc.Lock.Lock()
vc.Msg <- "in"
vc.Flag = true
vc.Lock.Unlock()
}
func Start(name string, password string, limit int) error {
runtime.GOMAXPROCS(4)
sl, err := sql.Open("mysql", name+":"+password+"@/xxx?charset=utf8")
defer sl.Close()
if err != nil {
return err
}
// 构造SELECT语句并检索
queryStr := "SELECT VolumeID, ImageUrl FROM volume "
if limit > 0 {
queryStr += "limit " + strconv.Itoa(limit)
}
rows, err := sl.Query(queryStr)
defer rows.Close()
if err != nil {
return err
}
// 构建列表
i := 0
vclist := make([]*VolumeCover, limit)
for rows.Next() {
vc := &VolumeCover{}
if err := rows.Scan(&vc.VolumeID, &vc.Url); err != nil {
return err
}
vc.Msg = make(chan string, 1)
//vc.To = make(chan bool, 1)
vc.Lock = *new(sync.Mutex)
vclist[i] = vc
i++
}
// start goroutines
for i := 0; i < len(vclist); i++ {
go SaveImage(vclist[i])
go func(i int) {
time.Sleep(TimeoutLimit * time.Second)
if vclist[i].Flag == false {
vclist[i].Msg <- "out"
}
}(i)
}
// 阻塞地获取结果
for i := 0; i < len(vclist); i++ {
func(c *VolumeCover) {
select {
case m := <-c.Msg:
fmt.Println(m)
}
}(vclist[i])
}
return nil
}
11、crawer:
package main
import (
"fmt"
"io"
"net/http"
"os"
"strconv"
)
func Get(url string) (result string, err error) {
resp, err1 := http.Get(url)
if err != nil {
err = err1
return
}
defer resp.Body.Close()
//读取网页的body内容
buf := make([]byte, 4*1024)
for true {
n, err := resp.Body.Read(buf)
if err != nil {
if err == io.EOF {
fmt.Println("文件读取完毕")
break
} else {
fmt.Println("resp.Body.Read err = ", err)
break
}
}
result += string(buf[:n])
}
return
}
//将所有的网页内容爬取下来
func SpiderPage(i int, page chan<- int) {
url := "https://github.com/search?q=go&type=Repositories&p=1" + strconv.Itoa((i-1)*50)
fmt.Printf("正在爬取第%d个网页\n", i)
//爬,将所有的网页内容爬取下来
result, err := Get(url)
if err != nil {
fmt.Println("http.Get err = ", err)
return
}
//把内容写入到文件
filename := "page"+strconv.Itoa(i) + ".html"
f, err1 := os.Create(filename)
if err1 != nil {
fmt.Println("os.Create err = ", err1)
return
}
//写内容
f.WriteString(result)
//关闭文件
f.Close()
//每爬完一个,就给个值
page <- i
}
func Run(start, end int) {
fmt.Printf("正在爬取第%d页到%d页\n", start, end)
//因为很有可能爬虫还没有结束下面的循环就已经结束了,所以这里就需要且到通道
page := make(chan int)
for i := start; i <= end; i++ {
//将page阻塞
go SpiderPage(i, page)
}
for i := start; i <= end; i++ {
fmt.Printf("第%d个页面爬取完成\n", <-page) //这里直接将面码传给点位符,值直接从管道里取出
}
}
func main() {
var start, end int
fmt.Printf("请输入起始页数字>=1:> ")
fmt.Scan(&start)
fmt.Printf("请输入结束页数字:> ")
fmt.Scan(&end)
Run(start, end)
}
package main
import (
"fmt"
"github.com/linehk/gopl/ch5/links"
"log"
)
func crawl(url string) []string {
fmt.Println(url)
list, err := links.Extract(url)
if err != nil {
log.Print(err)
}
return list
}
12、generator
package main
import "fmt"
// 生成自增的整数
func IntegerGenerator() chan int {
var ch chan int = make(chan int)
// 开启 goroutine
go func() {
for i := 0; ; i++ {
ch <- i // 直到通道索要数据,才把i添加进信道
}
}()
return ch
}
func main() {
generator := IntegerGenerator()
for i := 0; i < 100; i++ { //生成100个自增的整数
fmt.Println(<-generator)
}
}
13、goroutine
package main
import "fmt"
func main() {
messages := make(chan string)
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
}
package main
import (
"fmt"
"time"
)
func Echo(s string) {
for i := 0; i < 3; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go Echo("go")
Echo("web program")
}
14、multi-channel-recombination
package main
import (
"fmt"
"math/rand"
"time"
)
// 这里可以是比较耗时的事情,比如计算
func doCompute(x int) int {
time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond) //模拟计算
return 1 + x // 假如1 + x是一个很费时的计算
}
// 每个分支开出一个goroutine做计算,并把计算结果发送到各自通道
func branch(x int) chan int {
ch := make(chan int)
go func() {
ch <- doCompute(x)
}()
return ch
}
func Recombination(chs ...chan int) chan int {
ch := make(chan int)
for _, c := range chs {
// 注意此处明确传值
go func(c chan int) { ch <- <-c }(c) // 复合
}
return ch
}
func Recombination(branches ...chan int) chan int {
ch := make(chan int)
//select会尝试着依次取出各个通道的数据
go func() {
for i := 0; i < len(branches); i++ {
select {
case v1 := <-branches[i]:
ch <- v1
}
}
}()
return ch
}
func main() {
//返回复合结果
result := Recombination(branch(10), branch(20), branch(30))
for i := 0; i < 3; i++ {
fmt.Println(<-result)
}
}
package main
import (
"fmt"
"math/rand"
"time"
)
// 这里可以是比较耗时的事情,比如计算
func doCompute(x int) int {
time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond) //模拟计算
return 1 + x // 假如1 + x是一个很费时的计算
}
// 每个分支开出一个goroutine做计算,并把计算结果发送到各自通道
func branch(x int) chan int {
ch := make(chan int)
go func() {
ch <- doCompute(x)
}()
return ch
}
func Recombination(branches ...chan int) chan int {
ch := make(chan int)
//select会尝试着依次取出各个通道的数据
go func() {
for i := 0; i < len(branches); i++ {
select {
case v1 := <-branches[i]:
ch <- v1
}
}
}()
return ch
}
func main() {
//返回复合结果
result := Recombination(branch(10), branch(20), branch(30))
for i := 0; i < 3; i++ {
fmt.Println(<-result)
}
}
15、notification
package main
import "fmt"
func SendNotification(user string) chan string {
//......此处省略查询数据库获取新消息。
//声明一个通道来保存消息
notifications := make(chan string, 500)
// 开启一个通道
go func() {
//将消息放入通道
notifications <- fmt.Sprintf("Hi %s, welcome to our site!", user)
}()
return notifications
}
func main() {
barry := SendNotification("barry") // 获取barry的消息
shirdon := SendNotification("shirdon") // 获取shirdon的消息
// 获取消息的返回
fmt.Println(<-barry)
fmt.Println(<-shirdon)
}
16、picShow
package main
import (
"fmt"
"image"
"image/color"
"image/jpeg"
"io/ioutil"
"log"
"os"
"github.com/golang/freetype"
)
func main() {
//需要加水印的图片
imgfile, _ := os.Open("./pic.jpg")
defer imgfile.Close()
jpgimg, _ := jpeg.Decode(imgfile)
img := image.NewNRGBA(jpgimg.Bounds())
for y := 0; y < img.Bounds().Dy(); y++ {
for x := 0; x < img.Bounds().Dx(); x++ {
img.Set(x, y, jpgimg.At(x, y))
}
}
//拷贝一个字体文件到运行目录
fontBytes, err := ioutil.ReadFile("simsun.ttc")
if err != nil {
log.Println(err)
}
font, err := freetype.ParseFont(fontBytes)
if err != nil {
log.Println(err)
}
f := freetype.NewContext()
f.SetDPI(72)
f.SetFont(font)
f.SetFontSize(12)
f.SetClip(jpgimg.Bounds())
f.SetDst(img)
f.SetSrc(image.NewUniform(color.RGBA{R: 255, G: 0, B: 0, A: 255}))
pt := freetype.Pt(img.Bounds().Dx()-200, img.Bounds().Dy()-12)
_, err = f.DrawString("Shirdon", pt)
//draw.Draw(img,jpgimg.Bounds(),jpgimg,image.ZP,draw.Over)
//保存到新文件中
newfile, _ := os.Create("./aaa.jpg")
defer newfile.Close()
err = jpeg.Encode(newfile, img, &jpeg.Options{100})
if err != nil {
fmt.Println(err)
}
}
package main
import (
"image"
"image/color"
"image/draw"
"image/png"
"log"
"os"
)
func main() {
rectangle := "rectangle.png"
rectImage := image.NewRGBA(image.Rect(0, 0, 200, 200))
green := color.RGBA{0, 100, 0, 255}
draw.Draw(rectImage, rectImage.Bounds(), &image.Uniform{green}, image.ZP, draw.Src)
file, err := os.Create(rectangle)
if err != nil {
log.Fatalf("failed create file: %s", err)
}
png.Encode(file, rectImage)
}
17、race
package main
import "fmt"
func main() {
c := make(chan bool)
m := make(map[string]string)
go func() {
m["a"] = "one" // 第一个冲突访问.
c <- true
}()
m["b"] = "two" // 第一个冲突访问
<-c
for k, v := range m {
fmt.Println(k, v)
}
}
18、rand-generator
package main
import "fmt"
func randGenerator() chan int {
ch := make(chan int)
go func() {
for {
//select会尝试执行各个case, 如果都可以执行,那么随机选一个执行
select {
case ch <- 0:
case ch <- 1:
}
}
}()
return ch
}
func main() {
//初始化一个随机生成器
generator := randGenerator()
//测试,打印10个随机数
for i := 0; i < 10; i++ {
fmt.Println(<-generator)
}
}
19、sync_mutex
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var mutex sync.Mutex
wait := sync.WaitGroup{}
fmt.Println("Locked")
mutex.Lock()
for i := 1; i <= 5; i++ {
wait.Add(1)
go func(i int) {
fmt.Println("Not lock:", i)
mutex.Lock()
fmt.Println("Lock:", i)
time.Sleep(time.Second)
fmt.Println("Unlock:", i)
mutex.Unlock()
defer wait.Done()
}(i)
}
time.Sleep(time.Second)
fmt.Println("Unlocked")
mutex.Unlock()
wait.Wait()
}
20、sync_once
package main
import (
"fmt"
"sync"
)
func main() {
var once sync.Once
onceBody := func() {
fmt.Println("test only once,这里只打印一次!") //打印
}
done := make(chan bool)
for i := 0; i < 6; i++ {
go func() {
once.Do(onceBody) //确保只背执行一次
done <- true
}()
}
for i := 0; i < 6; i++ {
<-done
}
}
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
var once sync.Once
func func1(ch1 chan<- int) {
defer wg.Done()
for i := 0; i < 10; i++ {
ch1 <- i
}
close(ch1)
}
func func2(ch1 <-chan int, ch2 chan<- int) {
defer wg.Done()
for {
x, ok := <-ch1
if !ok {
break
}
ch2 <- 2 * x
}
once.Do(func() { close(ch2) }) // 确保某个操作只执行一次
}
func main() {
ch1 := make(chan int, 10)
ch2 := make(chan int, 10)
wg.Add(3)
go func1(ch1)
go func2(ch1, ch2)
go func2(ch1, ch2)
wg.Wait()
for ret := range ch2 {
fmt.Println(ret)
}
}
21、sync_rwmutex
package main
import (
"fmt"
"sync"
)
var sum int
var mutex sync.RWMutex
func Reader() {
mutex.RLock() //读锁
fmt.Printf("读到的是%d\n", sum)
defer mutex.RUnlock() //释放读锁
}
func Write() {
mutex.Lock()
defer mutex.Unlock()
sum += 2
}
func main() {
for x := 0; x < 10; x++ {
go Reader()
}
for x := 0; x < 10; x++ {
go Write()
}
for x := 0; x < 10; x++ {
go Write()
}
}
package main
import (
"fmt"
"sync"
)
func main() {
var num int
var wg sync.WaitGroup
var mutex sync.RWMutex
go func() {
defer wg.Done()
mutex.Lock()
num = 4
mutex.Unlock()
fmt.Printf("goroutine one, num=%d\n", num)
}()
go func() {
defer wg.Done()
mutex.Lock()
num = 5
mutex.Unlock()
fmt.Printf("goroutine two, num=%d\n", num)
}()
wg.Add(2)
wg.Wait()
fmt.Println("end main goroutine")
}
package main
import (
"fmt"
"math/rand"
"sync"
)
var count int
var rw sync.RWMutex
func main() {
ch := make(chan struct{}, 6)
for i := 0; i < 3; i++ {
go ReadCount(i, ch)
}
for i := 0; i < 3; i++ {
go WriteCount(i, ch)
}
for i := 0; i < 6; i++ {
<-ch
}
}
func ReadCount(n int, ch chan struct{}) {
rw.RLock()
fmt.Printf("goroutine %d 进入读操作...\n", n)
v := count
fmt.Printf("goroutine %d 读取结束,值为:%d\n", n, v)
rw.RUnlock()
ch <- struct{}{}
}
func WriteCount(n int, ch chan struct{}) {
rw.Lock()
fmt.Printf("goroutine %d 进入写操作...\n", n)
v := rand.Intn(10)
count = v
fmt.Printf("goroutine %d 写入结束,新值为:%d\n", n, v)
rw.Unlock()
ch <- struct{}{}
}
package main
import (
"sync"
"time"
)
var m *sync.RWMutex
func main() {
m = new(sync.RWMutex)
// 多个同时读
go Reading(1)
go Reading(2)
time.Sleep(2 * time.Second)
}
func Reading(i int) {
println(i, "reading start")
m.RLock()
println(i, "reading")
time.Sleep(1 * time.Second)
m.RUnlock()
println(i, "reading over")
}
package main
import (
"sync"
"time"
)
var m *sync.RWMutex
func main() {
m = new(sync.RWMutex)
// 写的时候啥也不能干
go Writing(1)
go Read(2)
go Writing(3)
time.Sleep(2 * time.Second)
}
func Read(i int) {
println(i, "reading start")
m.RLock()
println(i, "reading")
time.Sleep(1 * time.Second)
m.RUnlock()
println(i, "reading over")
}
func Writing(i int) {
println(i, "writing start")
m.Lock()
println(i, "writing")
time.Sleep(1 * time.Second)
m.Unlock()
println(i, "writing over")
}
22、sync_waitgroup
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println("1 goroutine sleep ...")
time.Sleep(2)
fmt.Println("1 goroutine exit ...")
}()
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println("2 goroutine sleep ...")
time.Sleep(4)
fmt.Println("2 goroutine exit ...")
}()
fmt.Println("Waiting for all goroutine ")
wg.Wait()
fmt.Println("All goroutines finished!")
}
package main
import (
"fmt"
"sync"
"time"
)
func main() {
testFunc := func(wg *sync.WaitGroup, id int) {
defer wg.Done()
fmt.Printf("%v goroutine start ...\n", id)
time.Sleep(2)
fmt.Printf("%v goroutine exit ...\n", id)
}
var wg sync.WaitGroup
const N = 3
wg.Add(N)
for i := 0; i < N; i++ {
go testFunc(&wg, i)
}
fmt.Println("Waiting for all goroutine")
wg.Wait()
fmt.Println("All goroutines finished!")
}
23、timer
package main
import (
"fmt"
"time"
)
func Timer(duration time.Duration) chan bool {
ch := make(chan bool)
go func() {
time.Sleep(duration)
// 到时间啦
ch <- true
}()
return ch
}
func main() {
// 定时5秒
timeout := Timer(5 * time.Second)
for {
select {
case <-timeout:
// 到时
fmt.Println("already 5s!")
//结束程序
return
}
}
}