go routine再解 并行问题|青训营笔记

67 阅读2分钟

这是我参与[第五届青训营]的第十三天

  • Web是基于HTTP协议进行交互的应用网络 HTTP1.1
  • Web就是通过使用浏览器/APP访问的各种资源

一般来说使用并行程序中,最常遇到的问题有:

  • 多线程相互通信
  • 等待一个程序结束后再接着工作
  • 多个并行程序使用同一个变量
  • 不同线程产出影响后续逻辑
  • 兄弟线程间共同同时结束

并发concurrency是将process切割成多个可执行单位(coroutine),如果有多个process时则在coroutine中交互执行,这样不会因为某一个process执行太久而造成其他process无法处理,会让我们有多工的感觉,但这并不会增加执行效率。

go routine的通信主要可以通过channel、全局变量进行操作。

首先channel的部分,声明通过chan关键字,配合make关键字申请空间。

package main
import(
    "fmt"
    "time"
)
//示例:channel控制线程,收集两个执行序的数据1、2
func main(){
    //宣告channel make(chan型态<容量>)
    val:= makechan int//执行第一个线程
    go func(){
        fmt.Println("intput val 1")
        val <- 1 //注入数据1
    }()
    //执行第二个线程
    go func(){
        fmt.Println("intput val 2")
        val <- 2 //注入数据2
        time.Sleep(time.Millisecond * 100)
    }()
    ans:= []int{}
    for {
        ans = append(ans,<-val)//取出数据
        fmt.Println(ans)
        if len(ans)== 2 {
            break
        }
    }
}

另一个方式就是比较传统的方式进行存取,直接使用变量进行存取,

package main
import(
    "fmt"
    "time"
)
//示例:共享变数
func main(){
    val:= 1
    //执行第一个线程
    go func(){
        fmt.Println("first",val)
    }()
    //执行第二个线程
    go func(){
        fmt.Println("sec",val)
    }()
    time.Sleep(time.Millisecond * 500)
}

如果比较熟悉Java的话可以联想到Join的概念,而在Golang中要做到等待的这件事情有两个方法,一个是sync.WaitGroup、另一个是channel。

Sync.WaitGroup像是一个计数器,启动一条Goroutine计数器+1;反之结束一条-1。若计数器为复数代表Error。

package main
import(
    "log"
    "sync"
    "time"
)
//示例:等待一线程结束后再接续工作(使用WaitGroup)
func main(){
var wg sync.WaitGroup
//执行线程
go func(){
defer wg.Done()//defer表示最后执行,因此该行为最后执行wg.Done()将计数器-1
defer log.Println("goroutine drop out")
log.Println("start a go routine")
time.Sleep(time.Second)//休息一秒钟
}()
wg.Add(1)//计数器+1
time.Sleep(time.Millisecond * 30)//休息30 ms
log.Println("wait a goroutine")
wg.Wait()//等待计数器归0
}