MENU

Go 学习笔记:并发编程

August 25, 2021 • Read: 276 • Golang

Go 语言提供了更加方便的并发编程方式(goroutine),通过go关键字调用新的协程,而不需要像java或者类似的语言去封装一些线程池之类的东西,这使得go语言对并发编程显得非常友好

我们可以很方便的新建一个协程

/*
 * @Author: NorthCityChen
 * @LastEditTime: 2021-08-25 15:15:43
 * @Description:
 * @Website: https://grimoire.cn
 * Copyright (c) NorthCityChen All rights reserved.
 */
package main

import (
    "fmt"
    "time"
)

func download() {
    fmt.Println("Download begins...")
    time.Sleep(time.Second * time.Duration(5))
    fmt.Println("Download successful")
}

func main() {
    fmt.Println("Main begins...")
    go download()
    fmt.Println("Main end")
}
/*
Main begins...
Main end
*/

通过运行这个程序,我们发现download函数好像根本没有运行!这是因为,这个程序在main函数推出后就结束了,而通过go关键字生成新的协程会花费一定的时间,这就导致,在主协程结束以后,所有的子协程都被强行结束,这就是为什么download函数根本没有运行。为了验证这个说法,我们让主协程多跑一会儿

/*
 * @Author: NorthCityChen
 * @LastEditTime: 2021-08-25 15:19:08
 * @Description:
 * @Website: https://grimoire.cn
 * Copyright (c) NorthCityChen All rights reserved.
 */
package main

import (
    "fmt"
    "time"
)

func download() {
    fmt.Println("Download begins...")
    time.Sleep(time.Second * time.Duration(5))
    fmt.Println("Download successful")
}

func main() {
    fmt.Println("Main begins...")
    go download()
    time.Sleep(time.Second * time.Duration(6))
    fmt.Println("Main end")
}
/*
Main begins...
Download begins...
Download successful
Main end
*/

可以看到这里子协程是已经正常运行了的。但是,我们以后所有的程序都需要使用sleep函数来阻塞么?这显然是不合理的,因此,go提供了一些其他的方法

比如使用sync方式

/*
 * @Author: NorthCityChen
 * @LastEditTime: 2021-08-25 15:23:44
 * @Description:
 * @Website: https://grimoire.cn
 * Copyright (c) NorthCityChen All rights reserved.
 */
package main

import (
    "fmt"
    "sync"
    "time"
)

var wg sync.WaitGroup

func download() {

    fmt.Println("Download begins...")
    time.Sleep(time.Second * time.Duration(5))
    fmt.Println("Download successful")
    wg.Done()
}

func main() {
    wg.Add(1)
    fmt.Println("Main begins...")
    go download()
    wg.Wait()
    fmt.Println("Main end")
}

这种方式要求所有的子协程之间没有通信,主协程会一直阻塞,直到所有的子协程都结束

那么,如果我们的子协程之间需要通信呢?是的,go也提供了通道(channel)的方式来解决这个问题

/*
 * @Author: NorthCityChen
 * @LastEditTime: 2021-08-25 15:28:44
 * @Description:
 * @Website: https://grimoire.cn
 * Copyright (c) NorthCityChen All rights reserved.
 */
package main

import (
    "fmt"
    "time"
)

var ch = make(chan string, 10)

func download() {

    fmt.Println("Download begins...")
    sleepTime := time.Second * time.Duration(5)
    time.Sleep(sleepTime)
    fmt.Println("Download successful")
    ch <- sleepTime.String()
}

func main() {
    fmt.Println("Main begins...")
    go download()
    go download()
    go download()
    for i := 0; i < 3; i++ {
        msg := <-ch
        fmt.Println(msg)
    }
    fmt.Println("Main end")
}

通道依然会阻塞主协程,等待子协程的结束,但是允许协程之间的数据交换

Archives Tip
QR Code for this page
Tipping QR Code