为了账号安全,请及时绑定邮箱和手机立即绑定

初学go,求指教

自己实现了一个,然后看了下老师的视频,发现实现方式完全不一样。

不知道老师有没时间看下我这个例子,指导下有啥优缺点。

另外看完了老师关于goroutine的系列课程,收获很多,感谢感谢

package main


import (

"fmt"

"time"

"sync"

)


//材料结构体

type data struct {

uid int //区分每个材料,便于打印展示

id int //区分每种材料,便于打印展示

time int //清洗耗时

}


var wg sync.WaitGroup


//每种材料个数

// var count int = rand.Intn(10) + 1

var count int = 5

var chanA = make(chan data, count*3)

var chanB = make(chan data, count)

var chanC = make(chan data, count)


//获取当前毫秒级时间

func now() int64 {

return (int64)(time.Now().UnixNano() / 1000 / 1000)

}


//清理材料

func A(id int) {

for {

select {

case d := <- chanA : 

fmt.Printf("time:%d A车工人:%d,材料%d:%d 清洗中...\n", now(), id, d.id, d.uid)

time.Sleep((time.Duration)(d.time * 100) * time.Millisecond)

fmt.Printf("time:%d A车工人:%d,材料%d:%d 清洗完成\n", now(), id, d.id, d.uid)

//清理完成,放入加工管道

chanB <- d

default :

break

}

}

}


//加工材料

func B(id int) {

cnt := 0

for {

select {

case d := <- chanB : 

fmt.Printf("time:%d B车工人:%d,材料%d:%d 加工中...\n", now(), id, d.id, d.uid)

time.Sleep(100 * time.Millisecond)

fmt.Printf("time:%d B车工人:%d,材料%d:%d 加工完成\n", now(), id, d.id, d.uid)

//加工完成,放入装载管道

chanC <- d

cnt += 1

default :

}


if cnt >= count {

break

}

}

}


//装载材料

func C(id int) {

for {

select {

case d := <- chanC : 

fmt.Printf("time:%d C车工人:%d,材料%d:%d 装载中...\n", now(), id, d.id, d.uid)

time.Sleep(100 * time.Millisecond)

fmt.Printf("time:%d C车工人:%d,材料%d:%d 装载完成\n", now(), id, d.id, d.uid)

//清理完成,放入装载管道

wg.Done()

default :

}

}

}


func main() {

fmt.Println("demo start")

//声明3种材料需要的空间

var list []data = make([]data, count*3)

var d data

//填充3种材料的数据

for i := 0; i < count; i++ {

//填充第一种材料数据,清洗耗时6

d = data{uid : i, id : 1, time : 6}

list[i] = d

//填充第二种材料数据,清洗耗时3

d = data{uid : i, id : 2, time : 3}

list[i + count] = d

//填充第二种材料数据,清洗耗时3

d = data{uid : i, id : 3, time : 3}

list[i + count * 2] = d

}


//往清洗的管道按清洗时间长短填充

for i := 0; i < len(list); i++ {

chanA <- list[i]

}


//A车3个清洗工人

go A(1)

go A(2)

go A(3)


//B车3个加工工人

go B(1)

go B(2)

go B(3)


//C车3个装载工人

go C(1)

go C(2)

go C(3)


wg.Add(count*3)


wg.Wait()


fmt.Println("demo end")

}


正在回答

1 回答

package main

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

var global = sync.WaitGroup{}

// A车传送给B车的通道
var ch1 = make(chan *material, 3)

// B车传送给C车的通道
var ch2 = make(chan *material, 3)

// 食材
type material struct {
   // 食材名称
   name string
   // 食材数量
   count byte
   // A车处理所需花费时间,单位秒
   elapsedTimeA uint
   // B车处理所需花费时间,单位秒
   elapsedTimeB uint
   // C车处理所需花费时间,单位秒
   elapsedTimeC uint
}

func main() {
   global.Add(3)
   // 所有需要处理的食材
   materials := []*material{
      {"白菜", 12, 2, 1, 1},
      {"青菜", 12, 1, 1, 1},
      {"胡萝卜", 12, 1, 1, 1},
   }
   start := time.Now()
   go A(materials)
   go B()
   go C()
   global.Wait()
   cost := time.Since(start)
   fmt.Printf("总耗时:%s\n", cost)
}
func A(materials []*material) {
   fmt.Printf("A车出发\n")
   // 循环处理每种食材
   for _, ele := range materials {
      var worker = sync.WaitGroup{}
      worker.Add(3)
      // 3名工人分别处理每种食材的1/3
      for i := 0; i < 3; i++ {
         go func(index int, ele2 *material) {
            fmt.Printf("A车工人[%d]正在清洗食材[%s],数量[%d],预计耗时[%d]秒\n", index, ele2.name, ele2.count/3, ele2.elapsedTimeA)
            // 睡眠模拟处理食材耗时
            time.Sleep(time.Second * time.Duration(ele2.elapsedTimeA))
            worker.Done()
         }(i, ele)
      }
      // 等待所有工人都处理完毕后,把处理后的食材传送给B车
      worker.Wait()
      fmt.Printf("A车食材[%s]正在运往B车\n", ele.name)
      ch1 <- ele
   }
   fmt.Printf("A车任务结束\n")
   global.Done()
}

func B() {
   fmt.Printf("B车出发\n")
   // 循环处理3种食材
   for i := 0; i < 3; i++ {
      // 从通道取不到数据时会阻塞,只有通道关闭时ok才等于false,所以下面的if判断可以忽略
      ele, ok := <-ch1
      if !ok {
         break
      }
      fmt.Printf("B车接收到A车食材[%s]\n", ele.name)
      var worker = sync.WaitGroup{}
      worker.Add(3)
      for j := 0; j < 3; j++ {
         go func(index int, ele2 *material) {
            fmt.Printf("B车工人[%d]正在加工食材[%s],数量[%d],预计耗时[%d]秒\n", index, ele2.name, ele2.count/3, ele2.elapsedTimeB)
            // 睡眠模拟处理食材耗时
            time.Sleep(time.Second * time.Duration(ele2.elapsedTimeB))
            worker.Done()
         }(j, ele)
      }
      // 等待所有工人都处理完毕后,把处理后的食材传送给C车
      worker.Wait()
      fmt.Printf("B车食材[%s]正在运往C车\n", ele.name)
      ch2 <- ele
   }
   fmt.Printf("B车任务结束\n")
   global.Done()
}

func C() {
   fmt.Printf("C车出发\n")
   for i := 0; i < 3; i++ {
      // 从通道取不到数据时会阻塞,只有通道关闭时ok才等于false,所以下面的if判断可以忽略
      ele, ok := <-ch2
      if !ok {
         break
      }
      fmt.Printf("C车接收到B车食材[%s]\n", ele.name)
      var worker = sync.WaitGroup{}
      worker.Add(3)
      for j := 0; j < 3; j++ {
         go func(index int, ele2 *material) {
            fmt.Printf("C车工人[%d]正在装载食材[%s],数量[%d],预计耗时[%d]秒\n", index, ele2.name, ele2.count/3, ele2.elapsedTimeC)
            // 睡眠模拟处理食材耗时
            time.Sleep(time.Second * time.Duration(ele2.elapsedTimeC))
            worker.Done()
         }(j, ele)
      }
      worker.Wait()
   }
   fmt.Printf("C车任务结束\n")
   global.Done()
}


0 回复 有任何疑惑可以回复我~

举报

0/150
提交
取消
Go并发之魂:Goroutine深入浅出【程序人生中的“米其林三星级”并发实战】
  • 参与学习       5489    人
  • 解答问题       8    个

深入浅出Go并发核心:Goroutine,斩获Goroutine面试题。

进入课程

初学go,求指教

我要回答 关注问题
意见反馈 帮助中心 APP下载
官方微信