开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情
我会继续沿用上一节GO并发操作使用的例子(GO并发实例 - 掘金 (juejin.cn)),还是员工制作咖啡,只不过现在我们假设有两个咖啡机(两个核),能够在同一时刻制作多份咖啡。如何将并发代码改为并行代码呢?
- 在代码改写的时候,我们如何识别咖啡机呢?肯定是增加名称字段,如下:
type CoffeeMachine struct {
MachineName string
CoffeeName string
Gopher
Mlock sync.Mutex
}
- 对此,我们还需要增加一个初始化函数,也就是定义一个CoffeeMachine类型的数组,长度为2,然后对其初始化,如下:
var coffeeMachines = [2]CoffeeMachine{} //全局变量
func init() {
coffeeMachines[0] = CoffeeMachine{MachineName: "Machine1"}
coffeeMachines[1] = CoffeeMachine{MachineName: "Machine2"}
}
- 那到底哪个员工去用哪个咖啡机呢?我们可以指定员工ID为偶数的去0号机器,奇数的去1号机器。具体就是在MakeCoffee函数中根据GopherId选择数组中对应的machine。
coffeeMachine := &coffeeMachines[g.GopherId%2]
- 选择好machine之后就是打印信息,××员工在××机器上制作了××咖啡,之后就是取咖啡和喝咖啡,取咖啡的时候员工和咖啡机之间还是绑定的,所以需要改写参数列表
func (g *Gopher) TakeCoffee(coffeeMachine *CoffeeMachine)
TakeCoffee原来的参数列表为空,因为不需要,之前并发执行时,只有一台machine,不需要绑定,coffeeMachine对于TakeCoffee来说可以直接使用,但现在coffeeMachine有两种。
- 这次还改写了waitGroup,将wg.Done()写在函数里面了,而不是开一个匿名函数,写在函数调用的下一行。
func (g *Gopher) MakeCoffee(CoffeeName string, wg *sync.WaitGroup) {
.......这是代码............
wg.Done()
}
现在改写之后的所有代码: -multicore -coffeemachine.go -gopher.go -main.go
coffeemachine.go
package multicore
import "sync"
type CoffeeMachine struct {
MachineName string
CoffeeName string
Gopher
Mlock sync.Mutex
}
gopher.go
package multicore
import (
"fmt"
"sync"
"time"
)
type Gopher struct {
GopherName string
GopherId int
CoffeeName string
}
//实现MakeCoffee方法
//实现TakeCoffee方法
//实现DrinkCoffee方法
var coffeeMachines = [2]CoffeeMachine{} //全局变量
func init() {
coffeeMachines[0] = CoffeeMachine{MachineName: "Machine1"}
coffeeMachines[1] = CoffeeMachine{MachineName: "Machine2"}
}
func (g *Gopher) MakeCoffee(CoffeeName string, wg *sync.WaitGroup) {
//实现MakeCoffee方法
//没有coffee才能MakeCoffee
coffeeMachine := &coffeeMachines[g.GopherId%2]
coffeeMachine.Mlock.Lock()
if coffeeMachine.CoffeeName == "" {
coffeeMachine.CoffeeName = CoffeeName
coffeeMachine.Gopher = *g
fmt.Printf("%v is Making %v Coffee on Machine %v, his id is %v\n", g.GopherName, CoffeeName, coffeeMachine.MachineName, g.GopherId)
}
time.Sleep(5 * time.Second) //为了使得并行更加直观,我们在MakeCoffee睡眠5秒,其它go程也能在go程1完成makeCoffee之前另一个CoffeeMachine上makeCoffee
g.TakeCoffee(coffeeMachine)
coffeeMachine.Mlock.Unlock()
g.DrinkCoffee()
wg.Done()
}
func (g *Gopher) TakeCoffee(coffeeMachine *CoffeeMachine) {
//实现TakeCoffee方法
//有coffee才能TakeCoffee
if coffeeMachine.CoffeeName != "" {
g.CoffeeName = coffeeMachine.CoffeeName
fmt.Printf("name=%v id=%v is taking %v Coffee\n", g.GopherId, g.GopherName, g.CoffeeName)
coffeeMachine.CoffeeName = "" //取完coffee后,清空coffee
} else {
fmt.Printf("%v is Waiting for Coffee\n", g.GopherName)
}
}
func (g *Gopher) DrinkCoffee() {
//实现DrinkCoffee方法
//有coffee才能DrinkCoffee
if g.CoffeeName != "" {
fmt.Printf("name=%v id=%v is Drinking %v Coffee\n", g.GopherId, g.GopherName, g.CoffeeName)
} else {
fmt.Printf("%v has no coffee to drink\n", g.GopherName)
}
}
main.go
package main
import (
"Concurrency/multicore"
"runtime"
"sync"
)
func main() {
// runtime.GOMAXPROCS(1) // 1 CPU core
// gopher1 := onecore.Gopher{GopherName: "gopher1", GopherId: 1}
// gopher2 := onecore.Gopher{GopherName: "gopher2", GopherId: 2}
// var c = make(chan struct{})
// go func() {
// gopher1.MakeCoffee("Latte")
// gopher2.MakeCoffee("Luksusowa")
// c <- struct{}{}
// }()
// <-c
runtime.GOMAXPROCS(2) // 2 CPU cores
gopher1 := multicore.Gopher{GopherName: "gopher1", GopherId: 1}
gopher2 := multicore.Gopher{GopherName: "gopher2", GopherId: 2}
gopher3 := multicore.Gopher{GopherName: "gopher3", GopherId: 3}
gopher4 := multicore.Gopher{GopherName: "gopher4", GopherId: 4}
var wg sync.WaitGroup
wg.Add(4)
go gopher1.MakeCoffee("Latte", &wg)
go gopher2.MakeCoffee("Luksusowa", &wg)
go gopher3.MakeCoffee("BlueMoutine", &wg)
go gopher4.MakeCoffee("Luckin", &wg)
wg.Wait()
}
代码运行结果为:
gopher4 is Making Luckin Coffee on Machine Machine1, his id is 4
gopher1 is Making Latte Coffee on Machine Machine2, his id is 1
name=1 id=gopher1 is taking Latte Coffee
name=1 id=gopher1 is Drinking Latte Coffee
name=4 id=gopher4 is taking Luckin Coffee
gopher3 is Making BlueMoutine Coffee on Machine Machine2, his id is 3
name=4 id=gopher4 is Drinking Luckin Coffee
gopher2 is Making Luksusowa Coffee on Machine Machine1, his id is 2
name=3 id=gopher3 is taking BlueMoutine Coffee
name=3 id=gopher3 is Drinking BlueMoutine Coffee
name=2 id=gopher2 is taking Luksusowa Coffee
name=2 id=gopher2 is Drinking Luksusowa Coffee
可以看到,Luckin咖啡还没被取出后,Latte就在另外一条咖啡机上制作,所以我们实现了并发。并行时所有咖啡只能等待前面的咖啡被取出后才能Make。